简体   繁体   中英

Python : Using class variables incorrectly?

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 Bx

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

Everything was normal but when I assigned 3 to Ax I got this:

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

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

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 Bx 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 Bx = 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 Ax=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.

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)".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM