描述符和直接访问:Python参考

时间:2013-10-16 17:01:48

标签: python descriptor python-descriptors

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 

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))