2011-01-30 17 views
5

私はPythonの継承可能クラスとして "サブコマンド"システムを実装しようとしています。私は、静的メソッドとしてCommand.subcommandを実装し、私は私のTypeError: 'staticmethod' object is not callableを得た親クラスにサブコマンドを追加しようとしたまですべてがうまく働いていたクラス定義内でも使用できるクラス内のデコレータの定義

from command import Command 
import sys 

class MyCommand(Command): 
    @Command.subcommand 
    def foo(self): 
     print "this can be run as a subcommand" 

    def bar(self): 
     print "but this is a plain method and isn't exposed to the CLI" 

MyCommand()(*sys.argv) 

# at the command line, the user runs "mycommand.py foo" 

:私の期待のユースケースは、のようなものです。後知恵では、thisが動作しないことは明らかです:

class Command(object): 
    @staticmethod 
    def subcommand(method): 
     method.is_subcommand = True 

     return method 

    @subcommand 
    def common(self): 
     print "this subcommand is available to all child classes" 

私がこれまでに見つけた唯一の選択肢は、クラス定義が完了した後、それを注入し、その後、親クラスの外subcommandデコレータを宣言することです。

def subcommand(method): 
    method.is_subcommand = True 

    return method 

class Command(object): 
    @subcommand 
    def common(self): 
     print "this subcommand is available to all child classes" 

Command.subcommand = staticmethod(subcommand) 
del subcommand 

しかし、デコレータが追加される前にPythonを使用したことのない人物として、これは私にとって非常に気難しいものです。これを達成するよりエレガントな方法はありますか?

+0

最初の質問は、そのクラスがデコレータの束に使用されていない限り、クラスのメソッドとしてデコレータを実装する理由です。それが何であれ、なぜあなたはデコレータを「共通」にしていますか?あなたのクラスデザインがちょっと変わっているので、それはおそらくclunkyだと感じています。:) –

+0

このデコレータがあなたのために何を達成したいと考えていますか? Pythonは既に、サブコマンドが何であるかを知っています。なぜなら、他のサブクラスであるクラスを知っているからです。 –

+0

@Lennart - 純粋に輸入美学のため。私は 'import command ... class MyCommand(command.Command)'(冗長な感じ)や 'from command import * ... @ subcommand'(名前空間を汚染するような感じ)のファンではありませんでした。 –

答えて

5

私が考えることができるこの問題には2つの解決策があります。最も簡単なのは、あなたが親クラスでそれを使用して終わっ後に静的メソッドようにすることです:

class Command(object): 
    def subcommand(method): # Regular function in class definition scope. 
     method.is_subcommand = True 

     return method 

    @subcommand 
    def common(self): 
     print "this subcommand is available to all child classes" 

    subcommand = staticmethod(subcommand) 
    # Now a static method. Can no longer be called during class definition phase. 

これは、あなたがそれを行った後、あなたが親クラスで使用することはできませんという点でやや壊れやすいです静的メソッド。

class Command(object): 
    @staticmethod 
    def subcommand(method): 
     method.is_subcommand = True 

     return method 

class CommandBase(Command): 

    @Command.subcommand 
    def common(self): 
     print "this subcommand is available to all child classes" 

あなたは今CommandBase代わりのCommandからあなたのすべてのクラスを継承することができます。これを行うには、より堅牢な方法は、中間クラスを追加することです。

+0

これは驚くべきことです。クラスメソッドのデコレータを実行すると、クラス自体がまだ存在していない(メタクラスは最後に呼び出されます)が、依然としてサブコマンドが見つかったと思います。とにかくあなたの例は両方ともタイプミスをしています:最初に終わりの引用符がありません。おそらく、 '@ Command.subcommand'を二番目に意味していました。私は正しいですか? – 6502

+0

@ 6502私はタイプミスを修正しました。最初の例で 'subcommand'の定義を見ると、正規関数として定義されていることがわかります。すべてのメソッド定義は、 'subcommand'が見つかるスコープ内で起こるので、そのスコープ内でサブコマンドが見えるはずです。 – aaronasterling

+0

はいそれは意味があります...サブコマンドは、クラス本体の最後までローカル変数であり、その時点で辞書は構築され、メタクラスに送られます。それでも私は奇妙な文章を感じる。クラスステートメントの本体のwhileループ:-D ... – 6502

関連する問題