2013-07-26 138 views
53

我有一些问题列表副本列表:深拷贝在Python

所以我从'get_edge'得到E0后,我通过调用'E0_copy = list(E0)'使E0副本。在这里,我猜E0_copyE0的深层副本,我将E0_copy转换为'karger(E)'。但在主要功能。
为什么for循环之前的'print E0[1:10]'的结果与for循环之后的结果不一样?

下面是我的代码:

def get_graph(): 
    f=open('kargerMinCut.txt') 
    G={} 
    for line in f: 
     ints = [int(x) for x in line.split()] 
     G[ints[0]]=ints[1:len(ints)] 
    return G 

def get_edge(G): 
    E=[] 
    for i in range(1,201): 
     for v in G[i]: 
      if v>i: 
       E.append([i,v]) 
    print id(E) 
    return E 

def karger(E): 
    import random 
    count=200 
    while 1: 
     if count == 2: 
      break 
     edge = random.randint(0,len(E)-1) 
     v0=E[edge][0] 
     v1=E[edge][1]     
     E.pop(edge) 
     if v0 != v1: 
      count -= 1 
      i=0 
      while 1: 
       if i == len(E): 
        break 
       if E[i][0] == v1: 
        E[i][0] = v0 
       if E[i][1] == v1: 
        E[i][1] = v0 
       if E[i][0] == E[i][1]: 
        E.pop(i) 
        i-=1 
       i+=1 

    mincut=len(E) 
    return mincut 


if __name__=="__main__": 
    import copy 
    G = get_graph() 
    results=[] 
    E0 = get_edge(G) 
    print E0[1:10]    ## this result is not equal to print2 
    for k in range(1,5): 
     E0_copy=list(E0)   ## I guess here E0_coypy is a deep copy of E0 
     results.append(karger(E0_copy)) 
     #print "the result is %d" %min(results) 
    print E0[1:10]    ## this is print2 

提前感谢!

+1

此外,b = A [:]是一个浅合作PY。请参阅http://stackoverflow.com/questions/16270374/how-to-make-a-shallow-copy-of-a-list-in-python –

回答

103

E0_copy不是深层复制。您不使用list()进行深度复制(list(...)testList[:]都是浅拷贝)。

您使用copy.deepcopy(...)深拷贝名单。

deepcopy(x, memo=None, _nil=[]) 
    Deep copy operation on arbitrary Python objects. 

请参见下面的代码片段 -

>>> a = [[1, 2, 3], [4, 5, 6]] 
>>> b = list(a) 
>>> a 
[[1, 2, 3], [4, 5, 6]] 
>>> b 
[[1, 2, 3], [4, 5, 6]] 
>>> a[0][1] = 10 
>>> a 
[[1, 10, 3], [4, 5, 6]] 
>>> b # b changes too -> Not a deepcopy. 
[[1, 10, 3], [4, 5, 6]] 

现在看到deepcopy操作

>>> import copy 
>>> b = copy.deepcopy(a) 
>>> a 
[[1, 10, 3], [4, 5, 6]] 
>>> b 
[[1, 10, 3], [4, 5, 6]] 
>>> a[0][1] = 9 
>>> a 
[[1, 9, 3], [4, 5, 6]] 
>>> b # b doesn't change -> Deep Copy 
[[1, 10, 3], [4, 5, 6]] 
+1

Thanks.But我认为list()是一个深层复制,因为id( E0)不等于id(E0_copy)。你能解释为什么会发生? – Shen

+6

列表(...)不会递归地创建内部对象的副本。它只是创建最外层列表的副本,同时仍然引用上一个变量的内层列表,因此,当您更改内层列表时,更改会反映在原始列表和浅层副本中。 –

+0

您可以看到,浅拷贝通过检查id(a [0])== id(b [0])来引用内部列表,其中b = list(a),a是列表列表。 –

1

如果您list elementsimmutable objects那么你可以使用它,否则,您必须使用deepcopycopy模块。

你也可以用最短的路深副本list这样。

a = [0,1,2,3,4,5,6,7,8,9,10] 
b = a[:] #deep copying the list a and assigning it to b 
print id(a) 
20983280 
print id(b) 
12967208 

a[2] = 20 
print a 
[0, 1, 20, 3, 4, 5, 6, 7, 8, 9,10] 
print b 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10] 
+14

这不是Deep Copy。 –

+1

然后它是什么。它有两个不同的词典(你可以检查每个词的ID)具有相同的值。 –

+0

阅读[this](http://docs.python.org/2/library/copy.html),[:]只是创建一个浅拷贝,它不会递归地在其中创建对象的副本。 –

0

只是一个递归深层复制函数。

def deepcopy(A): 
    rt = [] 
    for elem in A: 
     if isinstance(elem,list): 
      rt.append(deepcopy(elem)) 
     else: 
      rt.append(elem) 
    return rt 

编辑:作为Cfreak提到的,这已经在copy模块来实现。

+2

没有理由在'copy'模块 – Cfreak

0

关于名单为一棵树,在Python DEEP_COPY可以最紧凑写成

def deep_copy(x): 
    if not isinstance(x, list): return x 
    else: return map(deep_copy, x) 
25

相信很多程序员都遇到了在那里他们被要求深拷贝一个或两个面试问题链表,但是这个问题并不像听起来那么简单!

在python

,有一个被称为“复制”了两个有用的功能

import copy 
copy.copy() 
copy.deepcopy() 

拷贝()是一个浅拷贝功能模块中,如果给定的参数是这样的化合物的数据结构,例如一个列表,那么Python将创建同一类型的另一个对象(在这种情况下,新的列表),但里面的老名单的一切,只有他们引用被复制

# think of it like 
newList = [elem for elem in oldlist] 

直观地说,我们可以假设deepcopy的()将遵循同样的模式,唯一不同的是,每个ELEM我们将递归调用deepcopy的,(就像mbcoder的答案)

但这错误!

deepcopy的()实际上保留原始化合物数据的图形结构:

a = [1,2] 
b = [a,a] # there's only 1 object a 
c = deepcopy(b) 

# check the result 
c[0] is a # return False, a new object a' is created 
c[0] is c[1] # return True, c is [a',a'] not [a',a''] 

这是棘手的部分,的deepcopy的()的处理的哈希表(字典在python)期间使用到图: “old_object REF到new_object REF”时,这防止不必要的重复,从而保持所复制的化合物的数据的结构

official doc

-1

这是更Python

my_list = [0, 1, 2, 3, 4, 5] # some list 
my_list_copy = list(my_list) # my_list_copy and my_list does not share reference now. 

注:这是不是与可变类型

+1

中重新实现标准'deepcopy()'函数,这是行不通的。我认为这可能只是一个检查。尝试将字典列表作为一个好例子 –

+0

@ShashankSingh是的,这不适用于字典列表,因为条目是引用标签(指向内存位置)。因此,用这种方法重复字典列表将创建一个新列表,但由于条目是字典,它们仍然会引用相同的内存位置。 –

3

列表安全如果列表中的内容是原始数据类型,你可以使用一个修真

new_list = [i for i in old_list] 

可以嵌套它像多维列表:

new_grid = [[i for i in row] for row in grid]