Mutable Class Variables¶
Description¶
class C:
var = []
val = 0
def __init__(self, val):
self.var.append(val)
self.val = val
x = C(1)
y = C(2)
What would be the output from printing the values of x and y?
Expected Result¶
y.var: [1]
y.val: 1
y.var: [1, 2]
y.val: 2
OR
y.var: [1,2]
y.val: 2
y.var: [1, 2]
y.val: 2
Actual Output¶
y.var: [1, 2]
y.val: 1
y.var: [1, 2]
y.val: 2
Why this causes confusion¶
Users who have become accustomed to other programming languages may expect that
Python’s class instances would not share values unless those values were static. If
this were the case, x.val
would also be 2, as that is what y
overwrote it to be.
What is happening¶
Python default class variables behave similarly to static variables in other languages, every individual instance of a class references the same class variable. However, if a default value is overridden it becomes local to the instance instead of overwriting the class variable.
Because there is a matching variable inside of the class, there is no need to keep looking at a wider scope for it and so the class variable is never checked.
Because when it was initialised, x
modified var
, but overwrote
val
, it still sees the changes y
made to var
, but is not
affected by further changes to val
, as these would exist in the class scope
and not the instance scope.
Demonstration¶
class C:
var = []
def __init__(self, x):
self.var.append(x)
def overrideVar(x):
self.var = [x]
x = C(1)
y = C(2)
y.overrideVar(x)
z= C(4)
print("x:", x.var)
print("y:", y.var)
print("z:", z.var)
Will output:
x: [1, 2, 4]
y: [3]
z: [1, 2, 4]
Proving (because z
can still access it) that the class variable remains
unchanged, but that the variable in y
’s instance scope has been overridden.