Search code examples
pythoninstance-variables

Class variables: "class list" vs "class boolean"


I don't understand the difference in the following example. One time an instance of a class can CHANGE the class variable of another instance and the other time it can't?

Example 1:

class MyClass(object):
    mylist = []

    def add(self):
        self.mylist.append(1)

x = MyClass()
y = MyClass()
x.add()
print "x's mylist: ",x.mylist
print "y's mylist: ",y.mylist

Output:

x's mylist: [1]

y's mylist: [1]

So here an instance x of class A was able to access and modify the class attribute mylist which is also an attribute of the instance y of A.

Example 2:

class MyBank(object):
    crisis = False

    def bankrupt(self) :
        self.crisis = True

bankX = MyBank()
bankY = MyBank()
bankX.bankrupt()
print "bankX's crisis: ",bankX.crisis
print "bankY's crisis: ",bankY.crisis

bankX's crisis: True

bankY's crisis: False

Why does this not work in this example?


Solution

  • In first case there is no assignment in add method:

    def add(self):
        self.mylist.append(1)  # NOT self.mylist = something
    

    In second case there is an assignment:

    def bankrupt(self) :
        self.crisis = True  # self.crisis = something
    

    When an attribute is set on instance, it is always set on particular instance only (it's put to instance's __dict__ atribute). Class __dict__ is unaffected.

    In first case there is no assignment, so standard look-up rules apply. Since there is no "mylist" in __dict__ attribute of instance, it falls back to class __dict__.

    Operation performed in add mutates value stored in MyClass.__dict__. That's why change is observable in all instances.

    Consider following snippet (it may explain your issue better):

    class MyClass:
        x = []
    
    x1 = MyClass()
    x2 = MyClass()
    x3 = MyClass()
    
    x1.x.append(1)
    
    print x1.x  # [1]
    print x2.x  # [1]
    print x3.x  # [1]
    assert x1.x is x2.x is x3.x
    
    x3.x = "new"  # now x3.x no longer refers to class attribute
    
    print x1.x # [1]
    print x2.x # [1]
    print x3.x # "new"
    assert x1.x is x3.x  # no longer True!