复制/深度复制和变量范围

时间:2012-04-21 03:02:11

标签: python

我在使用copy.copy()和copy.deepcopy()以及Python的范围时遇到了问题。我调用一个函数,一个字典作为参数传递。字典复制本地字典,但字典不保留复制的值。

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)

copy.deepcopy工作,在函数“foo”中,dict A具有localDict的内容。但是在“foo”的范围之外,dict A是空的。同时,在分配了一个键和值后,dict B在退出函数'foo'后保留该值。

如何维护copy.deepcopy()复制到函数“foo”之外的值?

3 个答案:

答案 0 :(得分:1)

考虑一下:

>>> def foo(d):
...   d = {1: 2}
... 
>>> d = {3: 4}
>>> d
{3: 4}
>>> foo(d)
>>> d
{3: 4}
>>> 

foo内,d = {1: 2}将某个对象绑定到名称d。此名称是本地名称,不会修改用于指向的对象d。另一方面:

>>> def bar(d):
...   d[1] = 2
... 
>>> bar(d)
>>> d
{1: 2, 3: 4}
>>> 

所以这与你使用(深层)副本无关,它只是Python中“变量”的工作方式。

答案 1 :(得分:0)

正在发生的事情是在foo()内部创建一个B的副本并将其分配给A,通过将新对象重新分配给同一个名称来遮蔽您作为参数发送的空字典。现在在函数内部你有一个名为A的新dict,它与全局范围内的A outside完全无关,并且当函数结束时它会被垃圾收集,所以实际上没有任何反应,只有'me'键被添加到B中。

如果不是:

A = copy.deepcopy(localDict)

你做这样的事情,它会像你期望的那样工作:

C = copy.deepcopy(localDict)

A.update(C)

但看起来你真正想要的东西与复制模块无关,可能是这样的:

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'

答案 2 :(得分:0)

您看到的行为与deepcopy()无关,您将名称A重新分配给新值,除非您使用global,否则该分配不会延续关键词。 B更改持久的原因是您正在修改一个可变变量,以下是您可以获得所需行为的两个选项:

  • 不要使用localDict,只需修改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
    
  • 使用A.update(copy.deepcopy(localDict))代替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