Class Variables Behave Differently For List And Int?
Solution 1:
x.a.append(1)
changes the class attribute c.a
, a list
, by calling its append
method, which modifies the list in-place.
x.b += 1
is actually a shorthand for
x.b = x.b + 1
because integers in Python are immutable, so they don't have an __iadd__
(in-place add) method. The result of this assignment is to set an attribute b
on the instance x
, with value 2
(the result of evaluating the right-hand side of the assignment). This new instance attribute shadows the class attribute.
To see the difference between an in-place operation and an assignment, try
x.a += [1]
and
x.a = x.a + [1]
These will have different behavior.
EDIT The same functionality can be obtained for integers by boxing them:
classHasABoxedInt(object):
boxed_int = [0] # int boxed in a singleton list
a = HasABoxedInt()
a.boxed_int[0] += 1
b = HasABoxedInt()
print(b.boxed_int[0]) # prints 1, not zero
or
classBoxedInt(object):def__init__(self, value):
self.value = value
def__iadd__(self, i):
self.value += i
Solution 2:
larsmans' answer is excellent, but it might provide additional insight if we look at id
of x.b
before and after the assignment.
classc():
a=[1]
b=1def__init__(self):
pass
x=c()
print"initial a : {} at {}".format(x.a, id(x.a))
print"initial b : {} at {}".format(x.b, id(x.b))
x.a.append(1)
x.b+=1# x.b = x.b + 1, created a new object# we created an instance variable x.b and it# is shadowing the class variable b. print"after change a : {} at {}".format(x.a, id(x.a))
print"after change b : {} at {}".format(x.b, id(x.b))
y=c()
# We can already see from the class object that # b has not changed valueprint"in class c b : {} at {}".format(c.b, id(c.b))
print"in instance y a : {} at {}".format(y.a, id(y.a))
print"in instance y b : {} at {}".format(y.b, id(y.b))
Result:
initiala : [1]at50359040initialb : 1at40974280afterchangea : [1, 1]at50359040afterchangeb : 2at40974256 # Showsidofinstancevariablex.b; henceitis
# differentinclasscb : 1at40974280ininstanceya : [1, 1]at50359040ininstanceyb : 1at40974280
If you want to use an int
as a class variable, this should work:
classMyClass(object):
b=1def increase_b(self, n):
MyClass.b += n
Result:
>>>mc_1 = MyClass()>>>mc_1.b
1
>>>mc_1.increase_b(5)>>>mc_1.b
6
>>>mc_2 = MyClass()>>>mc_2.b
6
>>>mc_2.increase_b(10)>>>MyClass.b
16
>>>mc_2.b
16
>>>mc_1.b
16
Post a Comment for "Class Variables Behave Differently For List And Int?"