I have a python code snippet here:
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()
This prints out BACKUP BAR IS: {1: '1'}
the first two times, but then it starts to print out BACKUP BAR IS: {1: '42'}
the next eight times. Can anyone tell my how and why this is happening? Doesn't deepcopy
completely create a new instance of self
? How does the value of backup
bar change when we only change the value of "self", which is "a", in this case?
Edit: some have noted that the line self.bar = backup.bar
causes the two dicts to point to each other. But, if we do:
a = {1:1}
b = {1:2}
c = {1:3}
a = b
a = c
If a and b indeed point to the same dictionary, then all three values of a, b, c should be equal to c. But instead, a = c = {1:3}, b = {1:2}
. So changing the reference of the left hand side doesn't change the reference of the right hand side. Similarly, how would backup.bar
be changed if we're only changing self.bar
?
Setting self.bar = backup.bar
does not mutate the dictionary that self.bar
is pointing to, nor does it create a copy of backup.bar
to assign to self.bar
. Rather, it changes the pointer of self.bar
to refer to the dictionary at backup.bar
, so that they now refer to the same object. Take a look at this demonstration:
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'}
The discrepancy with iteration is explained by @alfasin.
With regard to your question edit, you never change the dictionary that b
points to. You're simply changing where a
is pointing to twice. a = c
does not mean change b = c. It simply means a was pointing to b, now it's pointing to c.
Edit drawings because why not.
a ---> {1: 1}
b ---> {1: 2}
c ---> {1: 3}
After a = b
:
a -------- # So long, {1: 1}
|
v
b ---> {1: 2}
c ---> {1: 3}
After a = c
, i.e., a points to what c points to:
a ---------------
|
|
b ---> {1: 2} |
c ---> {1: 3} <-|
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With