2012-03-20 4 views
2

関数/メソッドを調べてデコレータとして使用できるかどうかを確認することはできますか?それは、デコレータが他の関数をラップし、呼び出し可能なものを返す通常の方法に従いますか?具体的には、私はサードパーティのコードを検証するために探しています。メソッドがデコレータであるかどうかはどのように確認できますか?

+3

※デコレータとして使用することはできますか*、または*はどこかのデコレータとして使用されますか?最初のものは非常に難しいと証明できますが、一般的には解くことが不可能ではないにしても、2番目のものは実際に実行可能かもしれません。 –

+1

または機能が装飾されているかどうか尋ねていますか? – forivall

+0

@ NiklasB。申し訳ありません - 質問を明確にしました。 –

答えて

2

、その後、結果は__call__メソッドが含まれているかどうかをテストし、あなたが与えられた呼び出し可能がデコレータであるかないかどうかについての推測を作り出すことができます。しかし、それは単なる推測であり保証ではありません。

それ以外にも、Python言語の動的な型付けと、CPythonインタープリタの組み込み関数の特別な扱いのために、あなたが望むものは一般的には可能ではないと私は信じています。呼び出し可能オブジェクトが引数として別の呼び出し可能オブジェクトを受け入れるかどうか、またはその戻り値の型をプログラムで指定することはできません。また、CPythonでは、Cで実装された関数の場合、呼び出し可能な引数を調べて、受け入れる引数の数を確認することさえできません。

「デコレータ」という単語は、異なるものを意味すると解釈できます。それを定義する1つの方法は、デコレータは、単一の(呼び出し可能な)引数を受け取り、呼び出し可能なものを返す呼び出し可能なものです。

この定義では「関数」という単語を使用していないことにも注意してください。実際にそうするのは間違いでしょう。

  • ビルトインclassmethodstaticmethodデコレータ返す記述子オブジェクトではなく、機能:確かに、いくつかの一般的に使用されるデコレータは奇妙な性質を持っています。
  • 言語バージョン2.6以降では、関数やメソッドだけでなく、クラスを修飾することができます。
  • __init__(self, somecallable)メソッドと__call__(self, *args, **kwargs)メソッドを含む任意のクラスをデコレータとして使用できます。
+0

ありがとうございます - デコレータは "[呼び出し可能な引数を1つだけ受け入れて呼び出し可能なものを返す"]ことができるというステートメントは、私のテストの基礎になります。第三者コードで作成する必要があります。しかし、複雑さから判断すると、代わりに素晴らしいエラーメッセージを提供しようとしています。 :D –

0

私はこのようなことは一度もしていませんが、一般的に、このような状況では、「ダックタイピング」に依存しています。だから、ダミー関数を装飾し、呼び出し可能なものが返されたかどうかを調べることができます。

2

Pythonに標準化されたデコレータがないので、あなたが探しているデコレータについて何か分かっていない限り、関数がデコレータかどうかを伝える本当の方法はありません。

デコレータがあなたのコントロール下にある場合、装飾機能であることを示すマークを付けることができます。さもなければ、これを行う本当の統一された方法はありません。例えば、この例を取る:

def decorator(func): 
    return g 

@decorator 
def f() 
    pass 

def g(): 
    pass 

を上記の例では、実行時に、fおよびgは、同一となり、離れた2を伝える方法はありません。

0

これは不可能です。 fがデコレータであるかどうかを調べる代わりに、あなたはそれをチェックする必要があると思うべきですか?

あなたには、いくつかの特定のデコレータを期待している場合は、直接あなたには、いくつかの特定の動作/メソッドをしたい場合は/あなたには、いくつかの呼び出し可能fがデコレータとして使用することができるかどうかを確認したい場合は、

いることを確認することができます属性、かどうかを確認することができますいくつかのダミー関数を渡すことによってデコレータの動作をテストすることができますが、一般に、それは動作しないかもしれませんし、異なる入力に対して異なる動作をするかもしれません。ここで

は、このような素朴なチェックです:

def decorator1(func): 
    def _wrapper(*args, **kwargs): 
     print "before" 
     func(*args, **kwargs) 
     print "after" 

    return _wrapper 

def dummy_func(): pass 

out_func = decorator1(dummy_func) 

if callable(out_func) and dummy_func != out_func: 
    print "aha decorated!" 
+0

'ダミー関数を渡して直接確認できますか?? '実際には...あなたはそれがその議論と何をするのかを教えてはいけません! – katrielalex

+0

@katrielalexはい一般的な答えはいいえですが、デコレータが何をすべきか知っていれば、それを使って振る舞いを確認することができます –

1

引数の正しい数を持つ任意の呼び出し可能なデコレータとして使用することができます。 fooを返す可能性があるので

@foo 
def bar(...): 

は、当然のことながら

def bar(...): 
    ... 
bar = foo(bar) 

として 正確同じであることを忘れないでください、あなたは関数が飾られているか否かをチェックする方法がありません。 fooはいいかもしれませんが、マークを残すことはできますが、そうする必要はありません。あなたには、いくつかのPythonコードを与えている、あなたはデコレーターあるすべてのものを見つけたい場合は


、あなたがして装飾された機能を探してツリーを歩いて抽象構文木にコードを解析することによって行うことができます。次に、デコレータの.idを保存する例を示します。明らかに、あなたが望むならば、astオブジェクトを保存することができます。

例外をキャッチし、疑いのデコレータを適用することにより
>>> class DecoratorFinder(ast.NodeVisitor): 
...  def __init__(self, *args, **kwargs): 
...   super(DecoratorFinder, self).__init__(*args, **kwargs) 
...   self.decorators = set() 
...  
...  def visit_FunctionDef(self, node): 
...   self.decorators.update(dec.id for dec in node.decorator_list) 
...   self.generic_visit(node) 
... 
>>> finder = DecoratorFinder() 
>>> x = ast.parse(""" 
... @dec 
... def foo(): 
...  pass 
... """) 
>>> finder.visit(x) 
>>> finder.decorators 
set(['dec']) 
+0

実際には少なくとも1つの位置引数を取る呼び出し可能です。 –

+0

@Niklasあなたはもちろん正しい=) – katrielalex

関連する問題