Zgodzę się, że dziedziczenie lepiej pasuje do postawionego problemu.
Znalazłem to pytanie bardzo przydatne przy dekorowaniu klas, dziękuję wszystkim. Oto kolejne przykłady para, na podstawie innych odpowiedzi, takich jak dziedziczenie wpływa rzeczy w Pythonie 2.7 (i @wraps, który utrzymuje docstring pierwotnej funkcji jest, etc):
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...
często chcesz dodać parametry do dekoratora:
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()
Wyjścia:
@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
Użyłem dekorator funkcji, jak je znaleźć bardziej zwięzłe. Oto klasa ozdobić klasę:
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
bardziej wytrzymała wersja, która sprawdza tych nawiasach i działa, czy metody nie istnieją na zdobione klasy:
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
The assert
kontrole, które dekorator nie był używany bez nawiasów.Jeśli tak, to dekorowana klasa jest przekazywana do parametru dekoratora, który podnosi wartość AssertionError
.
@decorate_if
dotyczy tylko decorator
, jeśli condition
ma wartość .
getattr
, callable
testy, a @decorate_if
są wykorzystywane tak, że dekorator nie łamie jeśli metoda foo()
nie istnieje na klasę czym zdobione.
Chociaż jest to użyteczne, dekoratory Python różnią się od wzoru dekoratora. Mam niefortunne imię. Mogę jednak skończyć w ten sposób. Dzięki. –
@Robert Gowland: Bardzo dyplomatyczny. –