質問

I was looking at python's descriptor's documentation here, and the statement which got me thinking is:


For objects, the machinery is in object.__getattribute__() which transforms b.x into type(b).__dict__['x'].__get__(b, type(b))


under a section named Invoking Descriptors.

Last part of the statement b.x into type(b).__dict__['x'].__get__(b, type(b)) is causing the conflict here. As per my understanding, if we lookup for attribute on an instance, then instance.__dict__is being looked up, and if we didn't find anything type(instance).__dict__ is referred.

In our example, b.x should then be evaluated as:

b.__dict__["x"].__get__(b, type(b)) instead of

type(b).__dict__['x'].__get__(b, type(b))

Is this understanding correct? Or am I going wrong somewhere in interpretation? Any explanation would be helpful.

Thanks.

I am adding the second part as well:

Why instance attributes does not respect the descriptor protocol? For ex: referring to code below:

>>> class Desc(object):
...     def __get__(self, obj, type):
...         return 1000
...     def __set__(self, obj, value):
...         raise AttributeError
... 
>>> 
>>> class Test(object):
...     def __init__(self,num):
...         self.num = num
...         self.desc = Desc()
... 
>>> 
>>> t = Test(10)
>>> print "Desc details are ", t.desc
Desc details are  <__main__.Desc object at 0x7f746d647890>

Thanks for helping me out.

役に立ちましたか?

解決

Your understanding is incorrect. x most likely does not appear in the instance's dict at all; the descriptor object appears in the class's dict or the dict of one of the superclasses.

Let's use an example:

class Foo(object):
    @property
    def x(self):
        return 0

    def y(self):
        return 1

 x = Foo()
 x.__dict__['x'] = 2
 x.__dict__['y'] = 3

Foo.x and Foo.y are both descriptors. (Properties and functions both implement the descriptor protocol.)

When we access x.x:

>>> x.x
0

We do not get the value from x's dict. Instead, since Python finds a data descriptor by the name of x in Foo.__dict__, it calls

Foo.__dict__['x'].__get__(x, Foo)

and returns the result. The data descriptor wins over the instance dict.

On the other hand, if we try x.y:

>>> x.y
3

we get 3, rather than a bound method object. Functions don't have __set__ or __delete__, so the instance dict overrides them.


As for the new Part 2 to your question, descriptors don't function in the instance dict. Consider what would happen if they did:

class Foo(object):
    @property
    def bar(self):
        return 4

Foo.bar = 3

If descriptors functioned in the instance dict, then the assignment to Foo.bar would find a descriptor in Foo's dict and call Foo.__dict__['bar'].__set__. The __set__ method of the descriptor would have to handle setting the attribute on both the class and the instance, and it would have to tell the difference somehow, even in the face of metaclasses. There just isn't a compelling reason to complicate the protocol this way.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top