Reputation: 372
I'm having problems using copy.copy() and copy.deepcopy() and Python's scope. I call a function and a dictionary is passed as an argument. The dictionary copies a local dictionary but the dictionary does not retain the values that were copied.
def foo (A, B):
localDict = {}
localDict['name'] = "Simon"
localDict['age'] = 55
localDict['timestamp'] = "2011-05-13 15:13:22"
localDict['phone'] = {'work':'555-123-1234', 'home':'555-771-2190', 'mobile':'213-601-9100'}
A = copy.deepcopy(localDict)
B['me'] = 'John Doe'
return
def qua (A, B):
print "qua(A): ", A
print "qua(B): ", B
return
# *** MAIN ***
#
# Test
#
A = {}
B = {}
print "initial A: ", A
print "initial B: ", B
foo (A, B)
print "after foo(A): ", A
print "after foo(B): ", B
qua (A, B)
The copy.deepcopy works and within function "foo", dict A has the contents of localDict. But outside the scope of "foo", dict A is empty. Meanwhile, after being assigned a key and value, dict B retains the value after coming out of function 'foo'.
How do I maintain the values that copy.deepcopy() copies outside of function "foo"?
Upvotes: 0
Views: 1756
Reputation: 208505
The behavior you are seeing isn't related to deepcopy()
, you are reassigning the name A
to a new value, and that assignment will not carry over unless you use the global
keyword. The reason the changes to B
are persistent is that you are modifying a mutable variable, here are two options for how you could get the behavior you want:
Instead of using localDict
, just modify A
:
def foo(A, B):
A['name'] = "Simon"
A['age'] = 55
A['timestamp'] = "2011-05-13 15:13:22"
A['phone'] = {'work':'555-123-1234', 'home':'555-771-2190', 'mobile':'213-601-9100'}
B['me'] = 'John Doe'
return
Use A.update(copy.deepcopy(localDict))
instead of A = copy.deepcopy(localDict)
:
def foo(A, B):
localDict = {}
localDict['name'] = "Simon"
localDict['age'] = 55
localDict['timestamp'] = "2011-05-13 15:13:22"
localDict['phone'] = {'work':'555-123-1234', 'home':'555-771-2190', 'mobile':'213-601-9100'}
A.update(copy.deepcopy(localDict))
B['me'] = 'John Doe'
return
Upvotes: 0
Reputation: 273566
Ponder this:
>>> def foo(d):
... d = {1: 2}
...
>>> d = {3: 4}
>>> d
{3: 4}
>>> foo(d)
>>> d
{3: 4}
>>>
Inside foo
, d = {1: 2}
binds some object to the name d
. This name is local, it does not modify the object d
used to point to. On the other hand:
>>> def bar(d):
... d[1] = 2
...
>>> bar(d)
>>> d
{1: 2, 3: 4}
>>>
So this has nothing to do with your use of (deep)copy, it's just the way "variables" in Python work.
Upvotes: 1
Reputation: 41918
What's happening is that inside foo() you create a copy of B and assigns it to A, shadowing the empty dict you sent as an argument by reassigning a new object to the same name. Now inside the function you have a new dict called A, completely unrelated to the A outside in the global scope, and it gets garbage collected when the function ends, so actually nothing happens, only the 'me' key added to B.
If instead of:
A = copy.deepcopy(localDict)
You do something like this, it would work as you expect:
C = copy.deepcopy(localDict)
A.update(C)
But it seems like what you really want has nothing to do with the copy module and would be something like this:
def foo (A, B):
A['name'] = "Simon"
A['age'] = 55
A['timestamp'] = "2011-05-13 15:13:22"
A['phone'] = {'work':'555-123-1234', 'home':'555-771-2190', 'mobile':'213-601-9100'}
B['me'] = 'John Doe'
Upvotes: 0