10

I have the following classes:

class A(object):
    x = 1
class B(A):
    pass
class C(A):
    pass

When I print the value of x from each class I get:

>>>A.x, B.x, C.x
(1,1,1)

Then I assign 2 to B.x

B.x = 2
A.x, B.x, C.x
>>>(1,2,1)

Everything was normal but when I assigned 3 to A.x I got this :

A.x=3
A.x, B.x, C.x
>>>(3,2,3)

I thought it would return (3,2,1).

0

2 Answers 2

17

This is fundamentally how inheritance works in Python: for class-level variables, it first checks' the classes namespace, then the namespace of every class in the method resolution order. So, both B and C inherit x from A:

In [1]: class A(object):
   ...:     x = 1
   ...: class B(A):
   ...:     pass
   ...: class C(A):
   ...:     pass
   ...:

In [2]: vars(A)
Out[2]:
mappingproxy({'__module__': '__main__',
              'x': 1,
              '__dict__': <attribute '__dict__' of 'A' objects>,
              '__weakref__': <attribute '__weakref__' of 'A' objects>,
              '__doc__': None})

In [3]: vars(B)
Out[3]: mappingproxy({'__module__': '__main__', '__doc__': None})

In [4]: vars(C)
Out[4]: mappingproxy({'__module__': '__main__', '__doc__': None})

When you ask for B.x or C.x, it looks into that class namespace, doesn't find any "x", then tries A's namespace, finds it, and returns it.

Now, when you assign a variable to B.x = 2, that adds it to B's class namespace directly:

In [5]: B.x = 2
   ...:

In [6]: vars(B)
Out[6]: mappingproxy({'__module__': '__main__', '__doc__': None, 'x': 2})

And similarly, when you assign it to A.x=3, it overwrites the old value:

In [7]: A.x=3
   ...:

In [8]: vars(A)
Out[8]:
mappingproxy({'__module__': '__main__',
              'x': 3,
              '__dict__': <attribute '__dict__' of 'A' objects>,
              '__weakref__': <attribute '__weakref__' of 'A' objects>,
              '__doc__': None})

In [9]: vars(B)
Out[9]: mappingproxy({'__module__': '__main__', '__doc__': None, 'x': 2})

In [10]: vars(C)
Out[10]: mappingproxy({'__module__': '__main__', '__doc__': None})

So now, same as before, when you look for C.x, it doesn't find it's own, then it looks for x inside A, and finds it.

Note, inheritance works like this with instances too, just it checks the instance namespace first, then the instances class's namespace, then all the namespace of the classes in it's method resolution order.

Sign up to request clarification or add additional context in comments.

Comments

-1

I think it's because of this fact that you did not set "a" field for instance of the "C" class.

Thus it gets its default value from the superclass ("Parent class").

If you set the value of "a" in the c instance, You will get "(3,2,1)".

1 Comment

There is no instance of any of those classes in the example.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.