Sourabh Jaiswal
Sourabh Jaiswal

Reputation: 111

Sharing class variables in Python inheritance

I am confused with variable sharing concept in Python in inheritance.

Consider the following code:-

class a(object):
    var1 = 0
    var2 = {}
    def print_var(self):
        print(self.var1)
        print(self.var2)

class b(a):
    @classmethod
    def modify_var(cls):
        cls.var1 = 1
        cls.var2['temp']="something"

o1 = a()
o2 = b()
print("Initial Values")
o1.print_var()
o2.print_var()
print("Changing Values")
o2.modify_var()
print("Print values after change")
o1.print_var()
o2.print_var()

After running above code I can see the dictionary is being shared between child and parent class, but integer variable isn't.

Can anyone please explain this, or what I am doing wrong here?

Output of above code:

Initial Values
0
{}
0
{}
Changing Values
Print values after change
0    # <- this zero should be one according to my understanding
{'temp': 'something'}
1
{'temp': 'something'}

Upvotes: 6

Views: 3129

Answers (1)

James
James

Reputation: 36598

In general, you do not want to use mutable class variables. A class variable is shared by object reference to all instances of the class. But it is not shared across inherited classes.

So all instances of a share object references to a.var1 and a.var2. Similarly, all instances of b share object references to b.var1 and b.var2. Upon creating the inheritance, b also get the references to var1 and var2, but they are not shared back to a or any instantiations of a.

Because you use a mutable object for var2, the object's reference is never changed after the inheritance. So you can modify var2 and it will be modified for all references to it, because the object reference is the same.

If you reassign var2 instead of modifying it, you get the expected behavior.

Try this:

class a(object):
    var1 = 0
    var2 = {}
    def print_var(self):
        print(self.var1, end=', ')
        print(self.var2)

class b(a):
    @classmethod
    def modify_var(cls):
        cls.var1 = 1
        cls.var2 = {'temp': 'something'}  # reassign to a new dict

Here are some tests:

ob1 = a()
ob2 = b()

o1.print_var()
o2.print_var()

o2.modify_var()

o1.print_var()
o2.print_var()

# prints
0, {}
0, {}
0, {}
1, {'temp': 'something'}

Upvotes: 5

Related Questions