Descriptors and direct access: Python reference

偶尔善良 提交于 2019-12-24 10:56:53

问题


The python 3.3 documentation tells me that direct access to a property descriptor should be possible, although I'm skeptical of its syntax x.__get__(a). But the example that I constructed below fails. Am I missing something?

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

Here's the error I get in Python 2.7 (and also Python 3.2 after porting the snippet of code). The error message makes sense to me, but that doesn't seem to be how the documentation said it would work.

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:


By accessing the descriptor on self you invoked __get__ already. The value 42 is being returned.

For any attribute access, Python will look to the type of the object (so type(self) here) to see if there is a descriptor object there (an object with a .__get__() method, for example), and will then invoke that descriptor.

That's how methods work; a function object is found, which has a .__get__() method, which is invoked and returns a method object bound to self.

If you wanted to access the descriptor directly, you'd have to bypass this mechanism; access x in the __dict__ dictionary of Owner:

>>> Owner.__dict__['x']
<__main__.MyDescriptor object at 0x100e48e10>
>>> Owner.__dict__['x'].__get__(None, Owner)
hello
42

This behaviour is documented right above where you saw the x.__get__(a) direct call:

The default behavior for attribute access is to get, set, or delete the attribute from an object’s dictionary. For instance, a.x has a lookup chain starting with a.__dict__['x'], then type(a).__dict__['x'], and continuing through the base classes of type(a) excluding metaclasses.

The Direct Call scenario in the documentation only applies when you have a direct reference to the descriptor object (not invoked); the Owner.__dict__['x'] expression is such a reference.

Your code on the other hand, is an example of the Instance Binding scenario:

Instance Binding
If binding to an object instance, a.x is transformed into the call: type(a).__dict__['x'].__get__(a, type(a)).



来源:https://stackoverflow.com/questions/19409373/descriptors-and-direct-access-python-reference

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!