Search code examples
pythonooppython-class

How does Python keep track of changes in class attributes?


I bet there is an answer around, but unfortunately, I couldn't find it. When playing with classes, I found the following behaviour:

class C:
    i = 1
    
a = C()
b = C()
d = C()

b.i = 3
d.i = 4
print(C.i) # -> 1
print(a.i) # -> 1
print(b.i) # -> 3
print(d.i) # -> 4

d.i = 1
print(d.i) # -> 1

C.i = 5
print(C.i) # -> 5
print(a.i) # -> 5
print(b.i) # -> 3
print(d.i) # -> 1

Only the instances' class attributes, which weren't changed already, can be altered by changing the Class' class attribute. How is this behaviour internally checked? Is there a name for further reading?

Thanks!


Solution

  • There's nothing specific to "keep track" of.

    Simplifying things a bit, an attribute lookup a.i for class C's instance a looks for i in the instance's __dict__ first, then in the class's (and base classes') __dict__. (This is explained in more detail here in the context of descriptors.)

    Writing an attribute a.i = 5 only writes into the instance's __dict__. Writing C.i = 10 writes into the class's dict (and thus any instance that didn't have an i of its own would see 10.)

    >>> class C:
    ...     i = 1
    ...
    >>> a = C()
    >>> a.__dict__.get("i")
    # (nothing)
    >>> C.__dict__.get("i")
    1
    >>> a.i
    1
    >>> a.i = 5
    >>> a.__dict__.get("i")
    5
    >>> C.i = 10  # Update i on class
    >>> b = C()  # New instance with no i of its own
    >>> b.i
    10
    >>> a.i  # No change here, we have our own i
    5
    >>> del a.i  # Scrub the instance-specific `i`
    >>> a.i
    10