python 3.3 documentation告诉我应该可以直接访问属性描述符,尽管我对它的语法x.__get__(a)
持怀疑态度。但是我在下面构建的例子失败了。我错过了什么吗?
class MyDescriptor(object):
"""Descriptor"""
def __get__(self, instance, owner):
print "hello"
return 42
class Owner(object):
x = MyDescriptor()
def do_direct_access(self):
self.x.__get__(self)
if __name__ == '__main__':
my_instance = Owner()
print my_instance.x
my_instance.do_direct_access()
这是我在Python 2.7中获得的错误(以及移植代码片段后的Python 3.2)。错误信息对我来说很有意义,但这似乎并不是文档说它会起作用的方式。
Traceback (most recent call last):
File "descriptor_test.py", line 15, in <module>
my_instance.do_direct_access()
File "descriptor_test.py", line 10, in do_direct_access
self.x.__get__(self)
AttributeError: 'int' object has no attribute '__get__'
shell returned 1
答案 0 :(得分:3)
通过访问 self
上的描述符,您已经调用了__get__
。正在返回值42
。
对于任何属性访问,Python将查看对象的类型(这里是type(self)
)以查看是否存在描述符对象(例如,具有.__get__()
方法的对象) ,然后调用该描述符。
这就是方法的运作方式;找到一个函数对象,它有一个.__get__()
方法,该方法被调用并返回绑定到self的方法对象。
如果你想直接访问描述符,你必须绕过这个机制;访问x
__dict__
词典中的Owner
:
>>> Owner.__dict__['x']
<__main__.MyDescriptor object at 0x100e48e10>
>>> Owner.__dict__['x'].__get__(None, Owner)
hello
42
此行为记录在您看到x.__get__(a)
直接呼叫的上方:
属性访问的默认行为是从对象的字典中获取,设置或删除属性。例如,
a.x
的查询链以a.__dict__['x']
开头,然后是type(a).__dict__['x']
,并继续通过type(a)
的基类排除元类。
文档中的直接调用方案仅在您直接引用描述符对象(未调用)时适用; Owner.__dict__['x']
表达式就是这样的参考。
另一方面,您的代码是实例绑定方案的示例:
实例绑定
如果绑定到对象实例,a.x
将转换为调用:type(a).__dict__['x'].__get__(a, type(a))
。