1

python 3.3 文档告诉我应该可以直接访问属性描述符,尽管我对它的语法持怀疑态度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 
4

1 回答 1

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)直接调用的正上方:

属性访问的默认行为是从对象的字典中获取、设置或删除属性。例如,有一个以, thena.x开头的查找链,并继续通过排除元类的基类。a.__dict__['x']type(a).__dict__['x']type(a)

文档中的直接调用场景仅适用于直接引用描述符对象(未调用)的情况;Owner.__dict__['x']表达式就是这样的参考。

另一方面,您的代码是实例绑定方案的一个示例:

Instance Binding
如果绑定到一个对象实例,a.x则转换为调用:type(a).__dict__['x'].__get__(a, type(a))

于 2013-10-16T17:02:47.447 回答