Fundamentals 5 min read

Understanding Python Class and Instance Attribute Lookup Rules

This article explains Python’s dynamic attribute lookup mechanism, detailing how class and instance scopes differ, how attributes are searched and assigned, and demonstrates these concepts with concrete code examples that illustrate the impact on class versus instance state.

Python Programming Learning Circle
Python Programming Learning Circle
Python Programming Learning Circle
Understanding Python Class and Instance Attribute Lookup Rules

Generally, in Python, the access rules for class instance attributes are relatively straightforward, but there are some non‑intuitive aspects, especially for programmers coming from C++ or Java.

Key points to understand:

Python is a dynamic language; any object can have attributes added or removed at runtime.

A class defines its own scope.

An instance introduces a separate scope, distinct from the class scope.

When looking up an attribute on an instance, Python first searches the instance’s own scope, then the class’s scope if the attribute is not found.

Assigning to an attribute on an instance actually creates or updates the attribute in the instance’s scope, leaving the class’s attribute unchanged.

Consider the following example to deepen the understanding:

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

We create an instance a = A() and inspect the scopes of class A and instance a :

<code>a.dict
{'instance_j': {}, 'instance_i': 0}
A.dict
{'init': <function A.__init__>, 'module': 'main', 'cls_i': 0, 'cls_j': {}, 'doc': None}
</code>

The instance scope contains instance_i and instance_j , while the class scope contains cls_i and cls_j .

Attribute name lookup works as follows:

<code>a.cls_i
0
a.instance_i
0
</code>

When looking up cls_i , it is not found in the instance scope but is found in the class scope; instance_i is found directly in the instance scope.

If we try to modify cls_i via the instance:

<code>a.cls_i = 1
a.dict
{'instance_j': {}, 'cls_i': 1, 'instance_i': 0}
A.dict
{'init': <function A.__init__>, 'module': 'main', 'cls_i': 0, 'cls_j': {}, 'doc': None}
</code>

The instance now has its own cls_i attribute with value 1 , while the class attribute remains 0 ; we have added an instance attribute rather than changed the class attribute.

Modifying data inside the class attribute cls_j through the instance:

<code>a.cls_j['a'] = 'a'
a.dict
{'instance_j': {}, 'cls_i': 1, 'instance_i': 0}
A.dict
{'init': <function A.__init__>, 'module': 'main', 'cls_i': 0, 'cls_j': {'a': 'a'}, 'doc': None}
</code>

The instance scope does not change, but the class scope’s cls_j dictionary is updated, affecting all instances of the class.

Changes to the class scope affect every instance, including those created earlier:

<code>A.cls_k = 0
i = A()
i.cls_k
0
</code>

Thus, Python’s attribute lookup and assignment rules clearly separate instance and class namespaces, with modifications to the class namespace propagating to all instances.

Pythonobject-orientedClass AttributesDynamic LanguageAttribute Lookup
Python Programming Learning Circle
Written by

Python Programming Learning Circle

A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.