2012-07-30 15 views
66

Bir sınıf alanını argüman olarak bir sınıf yönteminde bir dekoratöre nasıl geçiririm?Python sınıfı yöntem çözücüsü öz argümanlarıyla mı?

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

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

O dekoratörüne self.url geçirilmesi için var olmadığını kendini yakınır: Ne yapmak istedikleri gibi bir şeydir. Bunun etrafında bir yolu var mı?

+0

Bu, üzerinde denetiminiz olan veya değiştiremediğiniz özel bir dekoratör mü? –

+0

Bu benim dekoratörüm, bu yüzden üzerinde tam kontrole sahibim. – Mark

+0

Init'ten önce çağrılır. Sorun şu ki ... –

cevap

98

Evet. Bunun yerine bir sınıf tanımı zamanda, örneğin özelliğinde geçme, zamanında kontrol: dekoratör yöntem bağımsız değişkenleri karşılar

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 

; İlk argüman örneğidir, bu yüzden özniteliği okur. Sen dekoratör için bir dize olarak Özellik adında geçmesi ve öznitelik adı kodlamalısınız istemiyorsanız getattr kullanabilirsiniz:

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

Yapamazsınız. Sınıfta self yoktur, çünkü örnek yoktur. Geri döndürme işlevinin daha sonra yapılabileceği örneğe bakmak için öznitelik adını içeren str kodunu ya da tamamen farklı bir yöntemi kullanmanız gerekir.

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() 

çıkışına: my_rule2: Tamam

+1

Çok teşekkür ederim! Bu kabul edilen cevap olmalı. Sınıf yöntemleri için dekoratörler bulmaya çalışırken saçlarımı yırtıyordum. – benshepherd

+0

@raphael Bu kurulumda _lambda veya pattern'e erişemiyorum. Bunu nasıl düzeltebilirim. – Jonathan

13

Daha

#/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) 

yazdırır Hangi aşağıdaki gibidir: özlü örnek olabilecek

kitty!