2012-04-21 33 views
0

我在使用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”中,字典A具有localDict的内容。但在“foo”的范围之外,字典A是空的。同时,在分配了一个键和值之后,字典B保留了函数'foo'出来后的值。

如何在函数“foo”之外保留copy.deepcopy()副本的值?

+0

为什么'foo'不能'返回localDict,B'并在代码中使用'A,B = foo(A,B)'?这样它*会*工作,你根本不需要使用'copy'模块。另外,阅读一下Python的对象引用:http://stackoverflow.com/questions/575196/in-python-why-can-a-function-modify-some-arguments-as-perceived-by-the-caller – Blender 2012-04-21 03:05:36

+0

@Blender,是的我知道我可以做到这一点,但我想知道为什么在字典按引用传递时,deepcopy()会导致Python中的字典存在范围问题。 – SQA777 2012-04-21 03:12:54

+0

它根本不是'deepcopy'或'copy'(你真的应该使用'dict(otherdict)'来复制,但那不是重点)。当你将一个对象传递给一个函数并且只能修改一些对象时,Python不能像PHP一样工作。阅读我链接到的问题的答案。 – Blender 2012-04-21 03:15:47

回答

0

发生了什么事情是在foo()中创建B的副本并将其分配给A,通过将新对象重新分配给同一名称来映射作为参数发送的空字典。现在函数里面有一个叫做A的新字典,与全局范围外的A完全无关,当函数结束时它会被垃圾收集,所以实际上什么也没有发生,只有'me'键被添加到B.

如果相反的:

A = copy.deepcopy(localDict)

你做这样的事情,它会按照您期望:

C = copy.deepcopy(localDict) 

A.update(C) 

但好像你真正想要的与复制模块无关,并且会是如此mething这样的:

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' 
1

思考这样的:

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

里面food = {1: 2}结合一些对象名称d。此名称是本地名称,它不会修改用于指向的对象d。另一方面:

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

所以这与您使用(深)复制无关,它只是Python中“变量”的工作方式。

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