class A:
@property
def p(self): return 2
def q(self): return 2
a = A()
A.p(a) #>> TypeError: 'property' object is not callable
A.q(a) #>> no error, returns 2
为什么是这样?我明白如果我引用实例上的属性:ap 只会返回方法返回值,但我试图从类上的属性开始。我预计上面没有错误,两者都评估为 2。
class A:
@property
def p(self): return 2
def q(self): return 2
a = A()
A.p(a) #>> TypeError: 'property' object is not callable
A.q(a) #>> no error, returns 2
为什么是这样?我明白如果我引用实例上的属性:ap 只会返回方法返回值,但我试图从类上的属性开始。我预计上面没有错误,两者都评估为 2。
你正在深入探索的世界descriptors
。 A.p
是 aproperty
并且属性是描述符。它是一个具有魔术方法(...)的类,__get__
当在实例__set__
上访问描述符时会调用这些方法。访问的特定方法当然取决于它的访问方式。访问类上的描述符只会返回描述符本身,并且不会执行任何魔法——在这种情况下,描述符是不可调用的,因此您会收到错误。property
注意如果你打电话会发生什么__get__
:
class A(object):
@property
def p(self):
return 2
a = A()
print (A.p.__get__(a)) #2
foo = A.p.__get__(a)
当你这样做时,实际上会发生什么foo = a.p
。我觉得还挺好看的...
因为属性不可调用:
In [3]: class A(object):
...: @property
...: def p(self): return 2
...:
In [4]: A.p
Out[4]: <property at 0x2d919a8>
In [5]: dir(A.p)
Out[5]:
['__class__',
'__delattr__',
'__delete__',
'__doc__',
'__format__',
'__get__',
'__getattribute__',
'__hash__',
'__init__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__set__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'deleter',
'fdel',
'fget',
'fset',
'getter',
'setter']
注意缺少__call__
方法。这是因为属性可以包含多个函数。
如果您尝试将属性作为实例上的方法调用,则会发生以下情况:
In [6]: a = A()
In [7]: a.p()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
C:\Users\Marcin\<ipython-input-7-16c8de382321> in <module>()
----> 1 a.p()
TypeError: 'int' object is not callable
属性装饰器将您的方法变成一个属性,它不再是一个函数对象,而是一个property
,因此不可调用