list deepcopy - 在Python中深層複製列表




file dict (7)

我對List副本有一些問題:

所以當我從'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

提前致謝!


Answers

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]]

關於作為樹的列表,python中的deep_copy可以最緊湊地編寫為

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

這更像是pythonic

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.

注意:對於可變類型列表,這是不安全的


我相信很多程序員遇到了一兩個面試問題,他們被要求深層複製鍊錶,但這個問題並不像聽起來那麼簡單!

在python中,有一個名為“copy”的模塊,它有兩個有用的功能

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

copy()是一個淺複製函數,如果給定的參數是一個複合數據結構,例如一個列表 ,那麼python將創建另一個相同類型的對象(在本例中是一個新列表 ),但對於舊列表中的所有內容,只複製他們的參考

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

直覺上,我們可以假設deepcopy()將遵循相同的範例,唯一的區別是對於每個元素我們將遞歸地調用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”,這可以防止不必要的重複,從而保留複製的複合數據的結構

官方文件


如果列表的內容是原始數據類型,則可以使用理解

new_list = [i for i in old_list]

您可以將其嵌套為多維列表,例如:

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

如果list elementsimmutable objects那麼您可以使用它,否則您必須使用copy模塊中的deepcopy

您也可以使用最短的方式深度複製這樣的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]

已經有很多答案告訴你如何製作正確的副本,但是他們都沒有說出你原來的“副本”失敗的原因。

Python不會將值存儲在變量中; 它將名稱綁定到對象。 您的原始任務使用了my_list引用的對象,並將其綁定到new_list 。 無論使用哪個名稱,仍然只有一個列表,因此將其引用為my_list時所做的更改將在以new_list引用時new_list 。 此問題的其他每個答案都為您提供了創建綁定到new_list的新對象的不同方法。

列表中的每個元素都像名稱一樣,因為每個元素都非唯一地綁定到對象。 淺拷貝創建一個新的列表,其元素與之前一樣綁定到相同的對象。

new_list = list(my_list)  # or my_list[:], but I prefer this syntax
# is simply a shorter way of:
new_list = [element for element in my_list]

要進一步將列表複製一步,請複制列表引用的每個對象,然後將這些元素副本綁定到新列表。

import copy  
# each element must have __copy__ defined for this...
new_list = [copy.copy(element) for element in my_list]

這還不是一個深層副本,因為列表中的每個元素都可能引用其他對象,就像列表綁定到其元素一樣。 要遞歸複製列表中的每個元素,然後復制每個元素引用的每個其他對象,依此類推:執行深度複製。

import copy
# each element must have __deepcopy__ defined for this...
new_list = copy.deepcopy(my_list)

有關複製中角落案例的更多信息,請參閱文檔







python list copy deep-copy