Dekorowanie metod klas Pythona - jak przekazać instancję dekoratorowi?
To jest Python 2.5, i to jest GAE też, nie żeby to miało znaczenie.
Mam następujący kod. Dekoruję metodę foo () w bar, używając klasy dec_check jako dekoratora.
class dec_check(object):
def __init__(self, f):
self.func = f
def __call__(self):
print 'In dec_check.__init__()'
self.func()
class bar(object):
@dec_check
def foo(self):
print 'In bar.foo()'
b = bar()
b.foo()
Podczas wykonywania tego miałem nadzieję zobaczyć:
In dec_check.__init__()
In bar.foo()
Ale dostaję "TypeError: foo() takes exactly 1 argument (0 given)
" jako .foo()
, będąc metodą obiektową, przyjmuje jaźń jako argument. Domyślam się, że problem polega na tym, że instancja bar
nie istnieje, gdy wykonuję dekoratora kod.
Jak przekazać instancję bar
do klasy dekoratorów?
3 answers
Musisz przekształcić dekorator w deskryptor -- albo przez upewnienie się, że jego (meta)klasa ma metodę __get__
, albo sposób prostszy, używając dekoratora Funkcja zamiast dekoratora klasa (ponieważ funkcje są już deskryptorami). Np.:
def dec_check(f):
def deco(self):
print 'In deco'
f(self)
return deco
class bar(object):
@dec_check
def foo(self):
print 'in bar.foo'
b = bar()
b.foo()
To wydruki
In deco
in bar.foo
Zgodnie z życzeniem.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-05 19:54:42
Odpowiedź Alexa wystarcza, gdy funkcja jest wystarczająca. Jednak, gdy potrzebujesz klasy, możesz sprawić, że będzie działać, dodając następującą metodę do klasy dekoratora.
def __get__(self, obj, objtype):
"""Support instance methods."""
import functools
return functools.partial(self.__call__, obj)
Aby to zrozumieć, musisz zrozumieć protokół deskryptora. Protokół deskryptora jest mechanizmem wiązania rzeczy z instancją. Składa się z __get__
, __set__
i __delete__
, które są wywoływane, gdy rzecz jest pobrana, ustawiona lub usunięta ze słownika instancji.
W tym przypadku, gdy rzecz ma z instancji wiążemy pierwszy argument jej metody __call__
z instancją, używając częściowego. Jest to wykonywane automatycznie dla funkcji Członkowskich, gdy klasa jest konstruowana, ale dla syntetycznej funkcji member, takiej jak ta, musimy to zrobić jawnie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-08 17:20:03
Jeśli chcesz napisać dekorator jako klasę możesz to zrobić:
from functools import update_wrapper, partial
class MyDecorator(object):
def __init__(self, func):
update_wrapper(self, func)
self.func = func
def __get__(self, obj, objtype):
"""Support instance methods."""
return functools.partial(self.__call__, obj)
def __call__(self, obj, *args, **kwargs):
print('Logic here')
return self.func(obj, *args, **kwargs)
my_decorator = MyDecorator
class MyClass(object):
@my_decorator
def my_method(self):
pass
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-20 12:23:53