2009-11-05 3 views
7

클래스 메소드에 사용할 데코레이터를 만들 때 데코레이터 메커니즘이 함수/클로저가 아닌 클래스 인 경우 문제가 있습니다. 클래스 폼을 사용할 때 내 데코레이터는 바운드 메서드로 처리되지 않습니다.데코레이터 메커니즘이 클래스 일 때 클래스 멤버의 파이썬 장식자가 실패합니다.

일반적으로 데코레이터에 함수 형식을 사용하는 것을 선호하지만이 경우 필자는 필요한 것을 구현하기 위해 기존 클래스를 사용해야합니다.

이것은 마치 python-decorator-makes-function-forget-that-it-belongs-to-a-class과 관련이있는 것처럼 보이지만 기능 양식에는 왜 문제가 있습니까?

다음은 모든 기능을 보여주는 가장 간단한 예입니다.

def decorator1(dec_param): 
    def decorator(function): 
     print 'decorator1 decoratoring:', function 
     def wrapper(*args): 
      print 'wrapper(%s) dec_param=%s' % (args, dec_param) 
      function(*args) 
     return wrapper 
    return decorator 

class WrapperClass(object): 
    def __init__(self, function, dec_param): 
     print 'WrapperClass.__init__ function=%s dec_param=%s' % (function, dec_param) 
     self.function = function 
     self.dec_param = dec_param 

    def __call__(self, *args): 
     print 'WrapperClass.__call__(%s, %s) dec_param=%s' % (self, args, self.dec_param) 
     self.function(*args) 

def decorator2(dec_param): 
    def decorator(function): 
     print 'decorator2 decoratoring:', function 
     return WrapperClass(function, dec_param) 
    return decorator 

class Test(object): 
    @decorator1(dec_param=123) 
    def member1(self, value=1): 
     print 'Test.member1(%s, %s)' % (self, value) 

    @decorator2(dec_param=456) 
    def member2(self, value=2): 
     print 'Test.member2(%s, %s)' % (self, value) 

@decorator1(dec_param=123) 
def free1(value=1): 
    print 'free1(%s)' % (value) 

@decorator2(dec_param=456) 
def free2(value=2): 
    print 'free2(%s)' % (value) 

test = Test() 
print '\n====member1====' 
test.member1(11) 

print '\n====member2====' 
test.member2(22) 

print '\n====free1====' 
free1(11) 

print '\n====free2====' 
free2(22) 

출력 :

decorator1 decoratoring: <function member1 at 0x3aba30> 
decorator2 decoratoring: <function member2 at 0x3ab8b0> 
WrapperClass.__init__ function=<function member2 at 0x3ab8b0> dec_param=456 
decorator1 decoratoring: <function free1 at 0x3ab9f0> 
decorator2 decoratoring: <function free2 at 0x3ab970> 
WrapperClass.__init__ function=<function free2 at 0x3ab970> dec_param=456 

====member1==== 
wrapper((<__main__.Test object at 0x3af5f0>, 11)) dec_param=123 
Test.member1(<__main__.Test object at 0x3af5f0>, 11) 

====member2==== 
WrapperClass.__call__(<__main__.WrapperClass object at 0x3af590>, (22,)) dec_param=456 
Test.member2(22, 2)  <<<- Badness HERE! 

====free1==== 
wrapper((11,)) dec_param=123 
free1(11) 

====free2==== 
WrapperClass.__call__(<__main__.WrapperClass object at 0x3af630>, (22,)) dec_param=456 
free2(22) 
+1

질문의 이름을 바꾸는 것이 좋습니다. 이것은 실제로 데코레이터와 관련이 없으며 대신 function 객체를 클래스 메소드로 추가하는 것입니다. – Casebash

+0

일반적으로 (항상 그런 것은 아니지만) 질문이 길면 문제를 격리하여 단순화 할 수 있습니다. 예를 들어, 클래스에 수동으로 주석을 달았 으면 데코레이터와 아무 관련이 없다는 것을 알았을 것입니다. 그리고 모든 코드를 타이핑하는 것보다 빠를 것입니다 – Casebash

답변

10

귀하의 WrapperClass 요구 될 수있는 기술자 (! 함수는 것처럼), 즉, 공급 적절한 특별한 방법 __get____set__ 코드의 양에 대한 죄송합니다. This how-to guide는 그것에 대해 알아야 할 모든 것을 가르칩니다. -)

관련 문제