This article describes how Python looks up an attribute on an object when it executes o.a
. The priority order is interesting - it looks for:
We can confirm this using the code below, which creates an object o
with an instance attribute a
, whose class contains a property of the same name:
class C:
def __init__(self):
self.__dict__['a'] = 1
@property
def a(self):
return 2
o = C()
print(o.a) # Prints 2
Why does Python use this priority order rather than the "naive" order (instance attributes take priority over all class attributes)? Python's priority order has a significant drawback: it makes attribute lookups slower, because instead of just returning an attribute of o
if it exists (a common case), Python must first search o
's class and all its superclasses for a data-descriptor.
What is the benefit of Python's priority order? It's presumably not just for the above situation, because having an instance variable and a property of the same name is very much a corner case (note the need to use self.__dict__['a'] = 1
to create the instance attribute, because the usual self.a = 1
would invoke the property).
Is there a different situation in which the "naive" lookup order would cause a problem?
In python, everything is an object. And every object has attributes and methods or functions. Attributes are described by data variables for example like name, age, height etc. Properties are special kind of attributes which have getter, setter and delete methods like __get__, __set__ and __delete__ methods.
Differences Between Class and Instance Attributes The difference is that class attributes are shared by all instances. When you change the value of a class attribute, it will affect all instances that share the same exact value. The attribute of an instance on the other hand is unique to that instance.
Object-Oriented Language One of the key features of Python is Object-Oriented programming. Python supports object-oriented language and concepts of classes, object encapsulation, etc.
Guido van Rossum himself (the ex-BDFL of Python) designed this feature when new-style classes were introduced with Python 2.2 back in 2001. The reasoning is discussed in PEP 252. The impact on attribute lookup is explicitly mentioned:
This scheme has one drawback: in what I assume to be the most common case, referencing an instance variable stored in the instance dict, it does two dictionary lookups, whereas the classic scheme did a quick test for attributes starting with two underscores plus a single dictionary lookup.
And:
A benchmark verifies that in fact this is as fast as classic instance variable lookup, so I'm no longer worried.
For old style classes (PEP 252):
The instance dict overrides the class dict, except for the special attributes (like
__dict__
and__class__
), which have priority over the instance dict.
Overriding the __dict__
or __class__
within the instance dict would break attribute lookup and cause the instance to behave in extremely weird ways.
In new-style classes, Guido chose the following implementation of attribute lookup to maintain consistency (PEP 252):
- Look in the type dict. If you find a data descriptor, use its
get()
method to produce the result. This takes care of special attributes like__dict__
and__class__
.- Look in the instance dict. If you find anything, that's it. (This takes care of the requirement that normally the instance dict overrides the class dict.)
- Look in the type dict again (in reality this uses the saved result from step 1, of course). If you find a descriptor, use its get() method; if you find something else, that's it; if it's not there, raise AttributeError.
In summary, the __dict__
and __class__
attributes are implemented as properties (data descriptors). To maintain a valid state, the instance dict cannot override __dict__
and __class__
. Thus, properties (data descriptors) take precedence over instance attributes.
What I want to know is, why do data descriptors take priority over instance attributes?
If there isn't some method that takes priority over normal instance lookup, how do you expect to intercept instance attribute accesses? These methods can't be instance attributes themselves because that would defeat their purpose (at least without additional conventions about them, I think).
Besides the concise comment of @timgeb, I can't explain anything about descriptors better than the official Descriptor How To
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With