2012-04-21 95 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