Python deepcopy,对象中的字典值更改
我这里有一段python代码片段:Python deepcopy,对象中的字典值更改,python,reference,copy,Python,Reference,Copy,我这里有一段python代码片段: import copy class Foo(object): bar = dict() def __init__(self, bar): self.bar = bar def loop(self): backup = copy.deepcopy(self) backup.bar[1] = "1" for i in range(0, 10): p
import copy
class Foo(object):
bar = dict()
def __init__(self, bar):
self.bar = bar
def loop(self):
backup = copy.deepcopy(self)
backup.bar[1] = "1"
for i in range(0, 10):
print "BACKUP BAR IS: ", backup.bar
self.bar[1] = "42"
self.bar = backup.bar
a = Foo({1:"0"})
a.loop()
前两次打印的备份条是:{1:'1'},但随后开始打印备份条是:{1:'42'}
接下来的八次。有人能告诉我这是怎么发生的以及为什么发生的吗?deepcopy
是否完全创建了self
的新实例?在这种情况下,当我们只更改“self”的值(即“a”)时,backup
bar的值如何变化
编辑:有些人注意到,行self.bar=backup.bar
导致两个dict相互指向。但是,如果我们这样做:
a = {1:1}
b = {1:2}
c = {1:3}
a = b
a = c
如果a和b确实指向同一个字典,那么a、b、c的三个值都应该等于c。但是相反,
a=c={1:3},b={1:2}
。因此,更改左手侧的参考并不会更改右手侧的参考。类似地,如果我们只更改self.bar
,如何更改backup.bar
?您的问题在于以下两行:
self.bar[1] = "42"
self.bar = backup.bar
在第一次迭代中,您确实没有更改backup.bar
,这就是为什么在第二次迭代开始时,它会再次打印{1:'1'}
但是,由于您设置了
self.bar=backup.bar
,然后通过更改self.bar
,实际上您正在更改backup.bar
,因为现在两者都指向同一对象。因此,从现在开始(第二次迭代-打印后),所有打印都将显示备份栏为:{1:'42'}(从第二次迭代开始,第二次赋值将是多余的,因为它们都指向同一个对象)。我相信您的问题在于这一行
self.bar = backup.bar
您正在将self.bar设置为现在指向backup.bar,因此当您修改self.bar时,您也在修改backup.bar,反之亦然设置
self.bar=backup.bar
不会变异self.bar
指向的词典,也不会创建backup.bar
的副本以分配给self.bar
。相反,它将self.bar
的指针更改为引用backup.bar
中的字典,以便它们现在引用相同的对象。看看这个演示:
In [48]: a = Foo({1: "0"})
In [49]: backup = copy.deepcopy(a)
In [50]: a.bar = backup.bar
In [51]: id(backup.bar)
Out[51]: 140428501511816
In [52]: id(a.bar) # Same object! Alternatively, `a.bar is backup.bar` -> True
Out[52]: 140428501511816
In [53]: backup.bar[1] = "42"
In [54]: a.bar
Out[54]: {1: '42'}
迭代的差异由@alfasin解释
关于问题编辑,您从不更改b
指向的词典。您只需更改a
指向两次的位置<代码>a=c并不意味着更改b=c。它只是意味着a指向b,现在它指向c
编辑图形,因为为什么不编辑
a ---> {1: 1}
b ---> {1: 2}
c ---> {1: 3}
在a=b
之后:
a -------- # So long, {1: 1}
|
v
b ---> {1: 2}
c ---> {1: 3}
在a=c
之后,即a指向c指向的对象:
a---------------
|
|
b--->{1:2}|
好的,这就是我想的,但是如果我们用普通字典试试这个:让a,b,c成为字典,设置a=b和a=c。当我在解释器中尝试这一点时,我不再得到b=c或a=b。@lu6cifer最好发布一个代码示例,因为理解注释中的“代码”有点问题。我希望您知道bar=dict()
和self.bar
是两个不同的对象(静态类成员和实例成员)在上一个示例中,您将b
分配给a
,然后将c
分配给a
,因此您最终将a
指向c
,但是b
没有改变,为什么您希望它也指向c
?
a ---------------
|
|
b ---> {1: 2} |
c ---> {1: 3} <-|