关于继承:Python:派生类在同一内存位置访问基类的字典

Python: derived classes access dictionary of base class in the same memory location

我想知道为什么一个字典,在一个基类中定义,并且从派生类中访问,显然只存在于一个内存位置中。一个简短的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class BaseClass:
    _testdict = dict()
    _testint = 0

    def add_dict_entry(self):
        self._testdict["first"] = 1

    def increment(self):
        self._testint += 1

class Class1(BaseClass):
    pass

class Class2(BaseClass):
    pass

object1 = Class1()
object2 = Class2()

object1.add_dict_entry()
object1.increment()
print(object2._testdict)
print(object2._testint)

输出为:

1
2
{'first': 1}
0

为什么对对象1的"添加字典项"的调用会影响对象2的字典?使用整数("增量")不会影响基类变量。

谢谢。

劳伦兹


这是因为_testdict是一个类变量:在最初构造类时,它只定义一次。如果希望它对每个实例都是单独的,请将其设置为实例变量:

1
2
3
4
5
6
7
8
class BaseClass:
    _testint = 0

    def __init__(self):
        self._testdict = dict()

    def add_dict_entry(self):
        self._testdict["first"] = 1

(请注意,您还需要为Class1Class2创建__init__方法,这两个方法都必须调用BaseClass.__init__(self))。

_testint的行为不同,因为您对它执行的是重新绑定操作,而不是变异操作。ints是不变的,所以你不能"改变"一个-self._testint += 1只是self._testint = self._testint + 1的语法糖。同样,您可以在self._testdict上执行不会在实例之间共享的重新绑定操作,例如,self._testdict = {}将只重置该实例的_testdict


在python中,int是不可变的,因此,+=操作会将类变量反弹到实例变量中。另一方面,字典索引会改变字典的位置。一个更具可比性的例子是

1
2
3
4
5
6
7
def add_dict_entry(self):
    # create a new dict
    tmp = dict(self._testdict)
    tmp["first"] = 1

    # shadow the class variable with an instance variables
    self._testdict = tmp