【问题标题】:Descriptors and direct access: Python reference描述符和直接访问:Python 参考
【发布时间】:2013-10-16 17:01:48
【问题描述】:

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(以及移植代码的 sn-p 后的 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 

【问题讨论】:

    标签: python descriptor python-descriptors


    【解决方案1】:

    通过访问 self 上的描述符,您已经调用了 __get__。正在返回值 42

    对于任何属性访问,Python 将查看对象的类型(此处为type(self))以查看那里是否存在描述符对象(例如,具有.__get__() 方法的对象),然后调用那个描述符。

    这就是方法的工作原理;找到一个函数对象,里面有一个.__get__()方法,被调用,返回一个绑定到self的方法对象。

    如果你想直接访问描述符,你必须绕过这个机制;在Owner__dict__字典中访问x

    >>> 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'] 表达式就是这样一个引用。

    另一方面,您的代码是 Instance Binding 场景的示例:

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

    【讨论】:

    • 好吧,我明白了。但是文档中有我使用的精确代码。那么文档有问题吗?
    • @gkb0986:文档中没有任何地方说x 是一个实例。
    • 我认为确实如此。 """直接调用最简单和最不常见的调用是用户代码直接调用描述符方法:x.__get__(a)。""" 不过我可能没有正确解析。
    • @gkb0986 文档没有错。在那个 sn-p x 是描述符对象的名称。 self.x 不评估描述符对象,它是属性访问,因此处理本文和文档中第二个 sn-p 说明的方式。
    • @gkb0986:对此进行了扩展;如果您确实有对描述符 itself 的引用,则只能直接调用;从self python 调用 Instance Binding 场景,您无法访问描述符,因为 Python 已经为您调用了它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-28
    • 2022-06-15
    • 2017-11-30
    • 1970-01-01
    • 1970-01-01
    • 2022-06-11
    • 1970-01-01
    相关资源
    最近更新 更多