Python class instance property access rules

  • 2020-04-02 14:30:50
  • OfStack

In general, the access rules for class instance properties are fairly straightforward in Python.

However, there are still some areas that are not very intuitive, especially for C++ and Java programmers.

Here, we need to understand the following:

Python is a dynamic language, and any entity can dynamically add or remove attributes.
2. A class defines a scope.
3. Class instances also introduce a scope that is different from the scope defined by the corresponding class.
4. When looking for properties in a class instance, first look in the scope of the instance itself, and if not, then look in the scope of the class definition.
5. When assigning a class instance property, you actually add a property (if it doesn't already exist) to the scope defined by the class instance, without affecting the property of the same name defined in the corresponding class.

Here is an example to deepen your understanding of the above points:


class A:
      cls_i = 0
      cls_j = {}
      def __init__(self):
            self.instance_i = 0
            self.instance_j = {}

Here, we define an instance of class A, and then look at the scope of class A and the scope of instance A:

>>> a = A()
>>> a.__dict__
{'instance_j': {}, 'instance_i': 0}
>>> A.__dict__
{'__init__': , '__module__': '__main__', 'cls_i': 0, 'cls_j': {}, '__doc__': None}

We can see that the scope of a has instance_i and instance_j, and the scope of a has cls_i and cls_j.

Let's take a look at how name lookup happens:


>>> a.cls_i
0
>>> a.instance_i
0

When looking for cls_i, it is not found in the scope of instance a, but it is found in the scope of a; When you look up instance_i, you can find it directly in the scope of a.

What happens if we try to modify the value of cls_i through instance a:


>>> a.cls_i = 1
>>> a.__dict__
{'instance_j': {}, 'cls_i': 1, 'instance_i': 0}
>>> A.__dict__
{'__init__': , '__module__': '__main__', 'cls_i': 0, 'cls_j': {}, '__doc__': None}

We can see that there is an extra cls_i attribute in the scope of a, which is 1; At the same time, we also notice that the value of cls_i attribute in A scope is still 0; In this case, we are actually adding an instance property, not modifying the class property.

What if we manipulate the data in cls_j (not cls_j itself, mind you) through instance a:


>>> a.cls_j['a'] = 'a'
>>> a.__dict__
{'instance_j': {}, 'cls_i': 1, 'instance_i': 0}
>>> A.__dict__
{'__init__': , '__module__': '__main__', 'cls_i': 0, 'cls_j': {'a': 'a'}, '__doc__': None}

We can see that the scope of a hasn't changed much, but the scope of a has changed a bit, and the data in cls_j has changed.

A change in the scope of an instance does not affect other instances of the class, but a change in the scope of the class affects all instances of the class, including those created earlier:


>>> A.cls_k = 0
>>> i.cls_k
0


Related articles: