【发布时间】:2013-03-12 22:56:17
【问题描述】:
当我尝试嵌套描述符/装饰器时,我很难理解会发生什么。我正在使用 python 2.7。
以property和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
试图嵌套它们:
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
内部描述符MyClassMethod 的__get__ 方法没有被调用。
由于无法弄清楚原因,我尝试输入(我认为是)一个无操作描述符:
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)
尝试在嵌套中使用无操作描述符/装饰器:
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
我不明白为什么 B().prop1 有效而 B().prop2 无效。
问题:
- 我做错了什么?为什么我会收到
object is not callable错误? - 正确的方法是什么?例如在重用
MyClassMethod和MyProperty(或classmethod和property)时定义MyClassProperty的最佳方式是什么
【问题讨论】:
-
直观理解这一点的关键是
@MyProperty创建的东西类似于 data 属性,而不是方法,因此您不能将其与方法描述符嵌套.这种直观的理解只能让你走这么远;完整的故事在 isedev 的回答中。
标签: python python-2.7 descriptor python-decorators