2012-07-30 8 views
66

クラスメソッドのデコレータにクラスフィールドを引数として渡すにはどうすればよいですか?それは、自己がデコレータにself.urlを渡すために存在していないと文句を言い自己引数を持つPythonクラスのメソッドデコレータ?

class Client(object): 
    def __init__(self, url): 
     self.url = url 

    @check_authorization("some_attr", self.url) 
    def get(self): 
     do_work() 

:私は何をしたいのようなものです。これを回避する方法はありますか?

+0

あなたがコントロールできるカスタムデコレータか、変更できないカスタムデコレータですか? –

+0

これは私のデコレータですので、私はそれを完全に制御しています – Mark

+0

initの前に呼び出されるのは問題だと思います... –

答えて

98

はい。代わりに、インスタンスに渡すの実行時に、それを確認し、クラス定義時に属性:

def check_authorization(f): 
    def wrapper(*args): 
     print args[0].url 
     return f(*args) 
    return wrapper 

class Client(object): 
    def __init__(self, url): 
     self.url = url 

    @check_authorization 
    def get(self): 
     print 'get' 

>>> Client('http://www.google.com').get() 
http://www.google.com 
get 

デコレータは、メソッドの引数をインターセプト。最初の引数はインスタンスなので、その属性を読み込みます。あなたはデコレータに文字列として属性名を渡すと、あなたは属性名をハードコーディングしたくない場合はgetattrを使用することができます。

def check_authorization(attribute): 
    def _check_authorization(f): 
     def wrapper(self, *args): 
      print getattr(self, attribute) 
      return f(self, *args) 
     return wrapper 
    return _check_authorization 
2

できません。インスタンスが存在しないため、クラス本体にはselfがありません。たとえば、属性名を含むstrを渡して、インスタンスで検索したり、返された関数が実行したり、別のメソッドを完全に使用したりする必要があります。

15
from re import search 
from functools import wraps 

def is_match(_lambda, pattern): 
    def wrapper(f): 
     @wraps(f) 
     def wrapped(self, *f_args, **f_kwargs): 
      if callable(_lambda) and search(pattern, (_lambda(self) or '')): 
       f(self, *f_args, **f_kwargs) 
     return wrapped 
    return wrapper 

class MyTest(object): 

    def __init__(self): 
     self.name = 'foo' 
     self.surname = 'bar' 

    @is_match(lambda x: x.name, 'foo') 
    @is_match(lambda x: x.surname, 'foo') 
    def my_rule(self): 
     print 'my_rule : ok' 

    @is_match(lambda x: x.name, 'foo') 
    @is_match(lambda x: x.surname, 'bar') 
    def my_rule2(self): 
     print 'my_rule2 : ok' 



test = MyTest() 
test.my_rule() 
test.my_rule2() 

出力に含ま: my_rule2:OK

+1

ありがとうございました!これは受け入れられた答えでなければなりません。私はクラスメソッドのデコレータを理解しようとしている私の髪を裂いていた。 – benshepherd

+0

@raphaelこの設定では、_lambdaまたはパターンにアクセスできないようです。どのように私はそれを改善することができます。 – Jonathan

13

詳細次のように簡潔な例は次のようになります。

印刷します
#/usr/bin/env python3 
from functools import wraps 

def wrapper(method): 
    @wraps(method) 
    def _impl(self, *method_args, **method_kwargs): 
     return method(self, *method_args, **method_kwargs) + "!" 
    return _impl 

class Foo: 
    @wrapper 
    def bar(self, word): 
     return word 

f = Foo() 
result = f.bar("kitty") 
print(result) 

kitty! 
関連する問題