Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Python, why do properties take priority over instance attributes?

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:

  1. A class attribute that is a data-descriptor (most commonly a property)
  2. An instance attribute
  3. Any other class attribute

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?

like image 338
user200783 Avatar asked Dec 16 '18 10:12

user200783


People also ask

What is the difference between attributes and properties in Python?

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.

What is the difference between class attributes and instance attributes Python?

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.

Which property of Python is important?

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.


3 Answers

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.

like image 142
fpbhb Avatar answered Oct 23 '22 22:10

fpbhb


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

  1. 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__.
  2. 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.)
  3. 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.

like image 30
Joshua Avatar answered Oct 23 '22 22:10

Joshua


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

like image 1
progmatico Avatar answered Oct 23 '22 22:10

progmatico