Trudno mi zrozumieć, co dzieje się, gdy próbuję zagnieździć deskryptory/dekoratory. Używam Pythona 2.7.Zagnieżdżanie deskryptorów/dekoratorów w pythonie
Na przykład, weźmy następujące uproszczone wersje property
i classmethod
:
class MyProperty(object):
def __init__(self, fget):
self.fget = fget
def __get__(self, obj, objtype=None):
print 'IN MyProperty.__get__'
return self.fget(obj)
class MyClassMethod(object):
def __init__(self, f):
self.f = f
def __get__(self, obj, objtype=None):
print 'IN MyClassMethod.__get__'
def f(*args, **kwargs):
return self.f(objtype, *args, **kwargs)
return f
Starając się zagnieździć je:
class A(object):
# doesn't work:
@MyProperty
@MyClassMethod
def klsproperty(cls):
return 555
# works:
@MyProperty
def prop(self):
return 111
# works:
@MyClassMethod
def klsmethod(cls, x):
return x**2
% print A.klsproperty
IN MyProperty.__get__
...
TypeError: 'MyClassMethod' object is not callable
__get__
metoda wewnętrznej deskryptorze MyClassMethod
nie nazywa uzyskiwanie. W przeciwnym razie, aby dowiedzieć się, dlaczego, próbowałem rzucać się (co moim zdaniem jest) deskryptor no-op:
class NoopDescriptor(object):
def __init__(self, f):
self.f = f
def __get__(self, obj, objtype=None):
print 'IN NoopDescriptor.__get__'
return self.f.__get__(obj, objtype=objtype)
próbuje użyć no-op deskryptora/dekorator w zagnieżdżania
class B(object):
# works:
@NoopDescriptor
@MyProperty
def prop1(self):
return 888
# doesn't work:
@MyProperty
@NoopDescriptor
def prop2(self):
return 999
% print B().prop1
IN NoopDescriptor.__get__
IN MyProperty.__get__
888
% print B().prop2
IN MyProperty.__get__
...
TypeError: 'NoopDescriptor' object is not callable
Nie rozumiem, dlaczego B().prop1
działa, a B().prop2
nie.
Pytania:
- Co robię źle? Dlaczego otrzymuję komunikat o błędzie
object is not callable
? - Jaka jest właściwa droga? na przykład co jest najlepszym sposobem definiowania
MyClassProperty
natomiast ponowne wykorzystanieMyClassMethod
iMyProperty
(lubclassmethod
iproperty
)
Kluczem do zrozumienia tego intuicyjnie jest to, że '@ MojaProperty' tworzy coś, co działa jak atrybut _data_, a nie metoda, więc nie można zagnieździć go za pomocą deskryptora metody. To intuicyjne zrozumienie dociera tylko do ciebie; cała historia jest w odpowiedzi Isedeva. – abarnert