मैं सहमत हूँ कि विरासत में मिली समस्या के लिए एक बेहतर फिट है।
मुझे यह प्रश्न वास्तव में आसान लगा, हालांकि सजाने वाली कक्षाओं पर, सभी का धन्यवाद।
अन्य उत्तरों के आधार पर, उदाहरणों का एक और युगल है, जिसमें शामिल है कि पायथन 2.7 में चीजें कैसे प्रभावित करती हैं, (और @wraps , जो मूल फ़ंक्शन के डॉकस्ट्रिंग, आदि को बनाए रखता है):
def dec(klass):
old_foo = klass.foo
@wraps(klass.foo)
def decorated_foo(self, *args ,**kwargs):
print('@decorator pre %s' % msg)
old_foo(self, *args, **kwargs)
print('@decorator post %s' % msg)
klass.foo = decorated_foo
return klass
@dec # No parentheses
class Foo...
अक्सर आप अपने डेकोरेटर में पैरामीटर जोड़ना चाहते हैं:
from functools import wraps
def dec(msg='default'):
def decorator(klass):
old_foo = klass.foo
@wraps(klass.foo)
def decorated_foo(self, *args ,**kwargs):
print('@decorator pre %s' % msg)
old_foo(self, *args, **kwargs)
print('@decorator post %s' % msg)
klass.foo = decorated_foo
return klass
return decorator
@dec('foo decorator') # You must add parentheses now, even if they're empty
class Foo(object):
def foo(self, *args, **kwargs):
print('foo.foo()')
@dec('subfoo decorator')
class SubFoo(Foo):
def foo(self, *args, **kwargs):
print('subfoo.foo() pre')
super(SubFoo, self).foo(*args, **kwargs)
print('subfoo.foo() post')
@dec('subsubfoo decorator')
class SubSubFoo(SubFoo):
def foo(self, *args, **kwargs):
print('subsubfoo.foo() pre')
super(SubSubFoo, self).foo(*args, **kwargs)
print('subsubfoo.foo() post')
SubSubFoo().foo()
आउटपुट:
@decorator pre subsubfoo decorator
subsubfoo.foo() pre
@decorator pre subfoo decorator
subfoo.foo() pre
@decorator pre foo decorator
foo.foo()
@decorator post foo decorator
subfoo.foo() post
@decorator post subfoo decorator
subsubfoo.foo() post
@decorator post subsubfoo decorator
मैंने एक फ़ंक्शन डेकोरेटर का उपयोग किया है, क्योंकि मैं उन्हें अधिक संक्षिप्त पाता हूं। यहाँ एक वर्ग को सजाने के लिए एक वर्ग है:
class Dec(object):
def __init__(self, msg):
self.msg = msg
def __call__(self, klass):
old_foo = klass.foo
msg = self.msg
def decorated_foo(self, *args, **kwargs):
print('@decorator pre %s' % msg)
old_foo(self, *args, **kwargs)
print('@decorator post %s' % msg)
klass.foo = decorated_foo
return klass
एक और अधिक मजबूत संस्करण जो उन कोष्ठकों के लिए जाँच करता है, और काम करता है अगर विधियाँ सजाया वर्ग पर मौजूद नहीं हैं:
from inspect import isclass
def decorate_if(condition, decorator):
return decorator if condition else lambda x: x
def dec(msg):
# Only use if your decorator's first parameter is never a class
assert not isclass(msg)
def decorator(klass):
old_foo = getattr(klass, 'foo', None)
@decorate_if(old_foo, wraps(klass.foo))
def decorated_foo(self, *args ,**kwargs):
print('@decorator pre %s' % msg)
if callable(old_foo):
old_foo(self, *args, **kwargs)
print('@decorator post %s' % msg)
klass.foo = decorated_foo
return klass
return decorator
assert
जांच करता है कि डेकोरेटर कोष्ठकों के बिना नहीं किया गया है। यदि यह है, तो सजाया जा रहा वर्ग msg
डेकोरेटर के पैरामीटर को पारित किया जाता है , जो एक उठाता हैAssertionError
।
@decorate_if
केवल decorator
अगर लागू होता है condition
मूल्यांकन करने के लिएTrue
।
getattr
, callable
परीक्षण, और @decorate_if
इसलिए उपयोग किया जाता है कि डेकोरेटर यदि नहीं तोड़ता है foo()
विधि वर्ग सजाया जा रहा है पर मौजूद नहीं है।