Skip to content Skip to sidebar Skip to footer

Class Variables Behave Differently For List And Int?

The class shared variables are shared with all the instances of the classes as far as I know. But I am having trouble getting my head around this. class c(): a=[1] b=1

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?"