2009-06-29 13 views
5

decorator pythonモジュール(3.0)の最新版を見ることには興奮しています。以前の反復よりもはるかに洗練されているように見える(たとえば、構文はこれまでよりも甘い)。Python Decorator 3.0とデコレータへの引数

しかし、それ自体が引数を取るデコレータにとっては、ひどいサポート(例えば、「ひどく伸びる隠喩」)があるようです。誰もあなたがきれいに 3.0を使ってこれを行う方法の良い例がありますか?

def substitute_args(fun, arg_sub_dict): 
     def wrapper(arg): 
     new_arg = arg_sub_dict.get(arg, arg) 
     return fun(new_arg) 

     # some magic happens here to make sure that type signature, 
     # __name__, __doc__, etc. of wrapper matches fun 

return wrapper 
+0

デコレータホーム:http://pypi.python.org/pypi/decorator/ –

答えて

7

この場合、関数をデコレータに戻す必要があります。 (何が間接の別のレベルでは解決することができます...)

from decorator import decorator 
def substitute_args(arg_sub_dict): 
    @decorator 
    def wrapper(fun, arg): 
    new_arg = arg_sub_dict.get(arg, arg) 
    return fun(new_arg) 
    return wrapper 

これはsubstitute_argsを意味することは、デコレータ工場だ、デコレータ自体ではありません。ここにはモジュールがない場合の等価物があります。 3つのレベルの深

def substitute_args(arg_sub_dict): 
    def my_decorator(fun): 
    def wrapper(arg): 
     new_arg = arg_sub_dict.get(arg, arg) 
     return fun(new_arg) 
    # magic to update __name__, etc. 
    return wrapper 
    return my_decorator 

非常に便利ではありませんが、関数が定義されている場合、それらの二つがある覚えている:

と同等です
@substitute_args({}) # this function is called and return value is the decorator 
def f(x): 
    return x 
# that (anonymous) decorator is applied to f 

:ここ

def f(x): 
    return x 
f = substitude_args({})(f) # notice the double call 
+0

これは非常に役に立ちました。ありがとう! – YGA

-2

は別です私はちょうど発見した方法:あなたのデコレータの最初の(そして唯一の)引数が呼び出し可能かどうかをチェックする;そうであれば、あなたは実行され、振る舞いを変更するラッパーメソッド(それ自体はfunctools.wrapsで飾られていて名前と文書の文字列を保持します)を返すことができます。

他の場合は、1つ以上の名前付き引数または位置指定引数が存在する必要があります。これらの引数を収集して、第1引数として呼び出し可能な呼び出し可能な呼び出し可能オブジェクトを返し、ラッパーメソッドを返します。その記述がデコレータメソッドの記述に合っているので、その非常にデコレータメソッドを返します。私はここでfunctools.partial私のデコレータのバージョンを取得するために使用したis_global_method(これは私が今すぐに取り組んでいる - その実装はもちろん、ナンセンスは以下に示すように、これはデコレーションの作品を示すためです)です。

この解決策は機能しているようですが、より多くのテストが必要です。あなたが私たちの目をくすぐるなら、そのトリックは覚えておくべきパターンとして3行か4行しかないことがわかります。私は別のデコレータにその種の機能をラップすることができますか?ああ、それのメ​​タネス!

from functools import wraps 
from functools import partial 

_    = print 
is_instance_of = isinstance 
is_callable  = lambda x: hasattr(x, '__call__') 

def is_global_method(x, *, name = None): 
    if is_callable(x): 
    @wraps(x) 
    def wrapper(*P, **Q): 
     return { 'name': name, 'result': x(*P, **Q), } 
    return wrapper 
    # assert is_instance_of(x, str) # could do some sanity checks here 
    return partial(is_global_method, name = x) 

@is_global_method 
def f(x): 
    """This is method f.""" 
    return x ** 2 

@is_global_method('foobar') 
def g(x): 
    """This is method g.""" 
    return x ** 2 

_(f.__name__) 
_(f.__doc__) 
_(f(42)) 
_(g.__name__) 
_(g.__doc__) 
_(g(42)) 
関連する問題