2

I'm curious on how inheritance works in case of dictionary mutations, I always thought that with each new instance the inherited classes get recreated.

class A(object):
    test = {"B": 0}

    def change_test(self, index):
        self.test["B"] += index

    def __init__(self, **kwargs):
        self.change_test(self.index)
        super(A, self).__init__(**kwargs)


class B(A):
    index = 1
    def print_test(self):
        print self.test


class C(A):
    index = 2
    def print_test(self):
        print self.test

b = B()
b.print_test()

c = C()
c.print_test()

Why does this return {'B': 1} {'B': 3} and not {'B': 1} {'B': 2}?

spedy
  • 2,200
  • 25
  • 26
  • 1
    test is actually a static variable: http://stackoverflow.com/questions/68645/static-class-variables-in-python – alpert Apr 28 '16 at 17:20

2 Answers2

3

The class variable test is shared among instances of A and its children.

print A.test is B.test # True
print B.test is C.test # True

Initally, test is {"B": 0}. When you initialize b, change_test from A is called because B inherits __init__ from A. So now test is {"B": 1}. After that, you initialize c, which leads to another call to change_test with index 2. Now test is {"B": 3} because 1 + 2 = 3.

timgeb
  • 76,762
  • 20
  • 123
  • 145
  • but why isn't this the case when A.test is an integer? – spedy Apr 28 '16 at 17:19
  • 1
    @spedy It works exactly the same way when `A.test` is an integer. It just does not have much consequences because integers are immutable anyway. But still, instances of `A`, `B`, and `C` would share the same integer object in memory. – timgeb Apr 28 '16 at 17:22
2

As already mentioned the variable is created at import-time and not recreated. This variable will be shared and because dict (but also list, ...) is mutable also changed by all instances of this class. To workaround it create the variable at instance-creation time:

class A(object):

    def change_test(self, index):
        self.test["B"] += index

    def __init__(self, **kwargs):
        self.test = {"B": 0}          # Create it here!!!
        self.change_test(self.index)
        super(A, self).__init__(**kwargs)

Normally only immutable types (int, ...) are save to use it as class-variables.


See also:

Community
  • 1
  • 1
MSeifert
  • 145,886
  • 38
  • 333
  • 352