我在这里有一个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):
print "BACKUP BAR IS: ", backup.bar
self.bar[1] = "42"
self.bar = backup.bar
a = Foo({1:"0"})
a.loop()
前两次打印出BACKUP BAR IS: {1: '1'}
,然后在接下来的八次打印出BACKUP BAR IS: {1: '42'}
。任何人都可以告诉我这是怎么回事以及为什么会这样? deepcopy
是否完全创建了self
的新实例?当我们只更改“self”的值时,backup
条的值如何变化,在这种情况下是“a”?
编辑:有人注意到行self.bar = backup.bar
导致两个词汇指向彼此。但是,如果我们这样做:
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}
。因此,改变左侧的参考不会改变右侧的参考。同样,如果我们只更改backup.bar
?
self.bar
答案 0 :(得分:4)
设置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
,之后,指向c指向的:
a ---------------
|
|
b ---> {1: 2} |
c ---> {1: 3} <-|
答案 1 :(得分:2)
您的问题在于以下两行:
self.bar[1] = "42"
self.bar = backup.bar
在第一次迭代中,你确实没有改变backup.bar
这就是为什么在第二次迭代开始时它再次打印{1:'1'}
。
但是,由于您设置了self.bar = backup.bar
,然后通过更改self.bar
,您实际上正在改变backup.bar
,因为现在两者都指向同一个对象。因此,从现在开始(第二次迭代 - 在打印之后),所有打印将显示BACKUP BAR IS: {1: '42'}
(并且从第二次迭代开始 - 第二次分配将是多余的,因为同样,两点都是到同一个对象)。
答案 2 :(得分:1)
我相信你的问题在于这一行
self.bar = backup.bar
您现在将self.bar设置为指向backup.bar,因此当您修改self.bar时,您也修改了backup.bar,反之亦然