I tried to google something about it. Why do non-data descriptors work with old-style classes?
Docs say that they should not:
"Note that descriptors are only invoked for new style objects or classes (ones that subclass object()
or type()
).".
class Descriptor(object):
def __init__(self):
self.x = 1
def __get__(self, obj, cls=None):
return self.x
class A:
x = Descriptor()
a = A()
a.x
>>> 1
Thanks.
You are right to question the documentation. I've tried looking through CPython sources to find an explanation, but be warned: I'm no expert.
From my understanding, attribute lookup and descriptor
__get__
invocation occurs ininstance_getattr2
(chosen extracts):So either I am missing something, or nothing in the implementation requires a new-style object (which contradicts the documentation).
For the record, I tried recompiling Python to restrict descriptor invocation to new style classes objects, but it actually brought up a gigantic mess. I learned in the process that class methods themselves are implemented as descriptors: this is the mechanism used to return bound or unbound method objects depending on the usage. For example:
As a result, it seems that preventing descriptor invocation for attributes of old-style objects or classes would also prevent method calls on them, at least with CPython implementation.
Once again, I'm no expert and this is the first time I dive into Python implementation, so I could very well be wrong. I've filed an issue to try to clarify this.