Python对词典很奇怪

lal*_*tin 0 python

当我执行这个python代码时,它会生成下面的输出.

class A(object):
    a = 0
    n = {}

    def inc(self):
        self.a += 1

    def add(self, key, obj):
        self.n[key] = obj

    def printn(self):
        print self.a
        print self.n


b = A()
c = A()

b.add("asf", "----")
c.add("asdf", "====")

b.inc()
c.inc()

b.printn()
c.printn()
Run Code Online (Sandbox Code Playgroud)

输出:

1
{'asf': '----', 'asdf': '===='}
1
{'asf': '----', 'asdf': '===='}
Run Code Online (Sandbox Code Playgroud)

aba*_*ert 5

这个问题与n作为字典无关; 它n是一个类属性而不是实例属性.这意味着该类的所有实例共享一个值.

解决方案只是将其转换为实例变量 - 将其分配到方法(通常是__init__方法)中而不是在类定义中.

class A(object):
    def __init__(self):
        self.n = {}
Run Code Online (Sandbox Code Playgroud)

你可能会问为什么同样的事情不会发生a.嗯,确实如此.您正在创建一个共享a,就像使用n.

但是你没有调用a那个改变它的共享上的任何方法(事实上​​,你不能,因为int它是不可变的;它没有任何改变它的方法).有了n,这self.n[key] = object可能看起来不像是方法调用(实际上是这样self.n.__setitem__(key, object)),但显而易见的是它正在改变n就地的值,这是关键所在.

你只需要分配一个新值self.a.这会创建一个新的实例属性,该属性会隐藏同名的class属性 - 这会让人感到困惑,但它可以按照您的意愿运行.n如果您只想构建一个新值并将其分配给以下内容,则可以获得相同的行为self.n:

def add(self, key, obj):
    new_n = copy.copy(n)
    new_n[key] = obj
    self.n = new_n
Run Code Online (Sandbox Code Playgroud)