In Python, why does updating a class attribute not update all instances of the class?

by wcarhart   Last Updated October 09, 2019 21:26 PM

Suppose I have the following class:

class A:
    arr = []

If I append to arr for an instance of A, all instances of A are updated.

>>> a1, a2 = A(), A()
>>> a1.arr.append(0)
>>> a1.arr
[0]
>>> a2.arr
[0]
>>> A.arr
[0]

However, if I set arr to an array literal for an instance of A, other instances are not updated:

>>> a1.arr = [1,2,3]
>>> a1.arr
[1, 2, 3]
>>> a2.arr
[0]
>>> A.arr
[0]

Why does this occur? When the class attribute is a list, why are there different results between append and =?

I also noticed similar behavior when the class attribute is not an array:

class B:
    value = ''
>>> b1, b2 = B(), B()
>>> b1.value = 'hello'
>>> b1.value
'hello'
>>> b2.value
''
>>> B.value
''
>>> B.value = 'goodbye'
>>> b1.value
'hello'
>>> b2.value
'goodbye'
>>> B.value
'goodbye'

Why does the behavior seem different when the class attribute is a string? When b1's value is already set, why does B.value = ... only update b2's value and not b1's?

Tags : python


Answers 3


If your asking how to avoid this?

class A:
    def __init__(self):
        self.ls = []
a,b = A(), A()
a.ls.append(0)

using

__init__() will make the instances individual

Yatish Kadam
Yatish Kadam
October 09, 2019 21:21 PM

I believe this answer explains what's happening.

In the class A, arr is a class attribute:

...all instances of Foo [A] share foovar [arr]

When you .append(), you're operating directly on the list object arr. When you assign (a1.arr = [1, 2, 3]), you're creating a new list object and assigning it as an instance attribute (effectively self.arr) on a1 that takes priority over the class attribute A.arr.

If we don't touch foovar, it's the same for both f and Foo. But if we change f.foovar... << code snippet >> ...we add an instance attribute that effectively masks the value of Foo.foovar. Now if we change Foo.foovar directly, it doesn't affect our foo instance:

b_c
b_c
October 09, 2019 21:25 PM

class C:
    class_attribute=2

    def __init__(self):
        self.instance_attribute='foo'

if you query an attribute of a class instance (my_instance.foo), the returned value is instance attribute if it exists, if not class attribute

if you assign to an instance(my_instance.foo = 42), a instance attribute is created, it can have the same name, and it shadows the class attribute

Derte Trdelnik
Derte Trdelnik
October 09, 2019 21:25 PM

Related Questions


Images dimensions error in python

Updated February 24, 2018 05:26 AM




How to test Python 3.4 asyncio code?

Updated July 28, 2017 22:26 PM