如何深层复制列表?

She*_*hen 111 python copy list deep-copy

我对List副本有一些问题:

所以我E0来之后'get_edge',我E0打电话给我'E0_copy = list(E0)'.在这里,我想E0_copy是的深层副本E0,和我通E0_copy'karger(E)'.但在主要功能.
为什么'print E0[1:10]'for循环之前的结果与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
Run Code Online (Sandbox Code Playgroud)

Suk*_*lra 189

E0_copy不是一个深刻的副本.你不使用深层副本list()(两者list(...)testList[:]很浅拷贝).

copy.deepcopy(...)用于深度复制列表.

deepcopy(x, memo=None, _nil=[])
    Deep copy operation on arbitrary Python objects.
Run Code Online (Sandbox Code Playgroud)

请参阅以下代码段 -

>>> 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]]
Run Code Online (Sandbox Code Playgroud)

现在看看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]]
Run Code Online (Sandbox Code Playgroud)

  • list(...)不会递归地复制内部对象.它只生成最外面列表的副本,同时仍然引用前一个变量的内部列表,因此,当您改变内部列表时,更改将反映在原始列表和浅层副本中. (11认同)
  • 谢谢.但我认为list()是一个深层副本,因为id(E0)不等于id(E0_copy).你能解释一下为什么会这样吗? (3认同)
  • 请记住,相对于列表切片(大约 20 倍),“copy.deepcopy”[极其慢](/sf/answers/4400566621/)。[在类中实现 `__deepcopy__`](/sf/answers/1104180941/) 可以帮助加快速度。 (2认同)

wat*_*HUN 54

我相信很多程序员遇到了一两个面试问题,他们被要求深层复制一个链表,但这个问题并不像听起来那么容易!

在python中,有一个名为"copy"的模块,它有两个有用的功能

import copy
copy.copy()
copy.deepcopy()
Run Code Online (Sandbox Code Playgroud)

copy()是一个浅复制函数,如果给定的参数是一个复合数据结构,例如一个列表,那么python将创建另一个相同类型的对象(在本例中是一个新列表),但对于旧列表中的所有内容,只复制他们的参考

# think of it like
newList = [elem for elem in oldlist]
Run Code Online (Sandbox Code Playgroud)

直觉上,我们可以假设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'']
Run Code Online (Sandbox Code Playgroud)

这是一个棘手的部分,在deepcopy()过程中,一个哈希表(python中的字典)用于映射:"old_object ref into new_object ref",这可以防止不必要的重复,从而保留复制的复合数据的结构

官方文件

  • 应更新深层复制文档,以在本答案末尾突出显示警告/示例。 (5认同)

Mys*_*tic 14

@苏克里特卡尔拉

No.1:list()[:]copy.copy()都是浅拷贝。如果一个对象是复合的,那么它们都不适合。你需要使用copy.deepcopy().

第二:b = a直接,a并且b有相同的引用,改变a就等于改变b

将a设置为b

如果直接分配aba共享b一个参考。

>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = a
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0] = 1
>>> a
[1, [4, 5, 6]]
>>> b
[1, [4, 5, 6]]


>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = 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
[[1, 10, 3], [4, 5, 6]]
Run Code Online (Sandbox Code Playgroud)

卷影副本

经过list()

list()并且[:]是相同的。除了第一层的更改外,所有其他层的更改都将被转移。

>>> 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
>>> a
[1, [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]


>>> 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
[[1, 10, 3], [4, 5, 6]]

Run Code Online (Sandbox Code Playgroud)

经过[:]

>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = a[:]
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0] = 1
>>> a
[1, [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]


>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = 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
[[1, 10, 3], [4, 5, 6]]

Run Code Online (Sandbox Code Playgroud)

list() 和 [:] 更改除第一层之外的其他层

# =========== [:] ===========
>>> a = [[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b = a[:]
>>> a
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> a[0][2] = 4
>>> a
[[1, 2, 4], [4, 5, 6]]
>>> b
[[1, 2, 4], [4, 5, 6]]


>>> a = [[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b = a[:]
>>> a
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> a[0][2][0] = 999
>>> a
[[1, 2, [999, 6]], [4, 5, 6]]
>>> b
[[1, 2, [999, 6]], [4, 5, 6]]



# =========== list() ===========
>>> a = [[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b = list(a)
>>> a
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> a[0][2] = 4
>>> a
[[1, 2, 4], [4, 5, 6]]
>>> b
[[1, 2, 4], [4, 5, 6]]


>>> a = [[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b = list(a)
>>> a
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> a[0][2][0] = 999
>>> a
[[1, 2, [999, 6]], [4, 5, 6]]
>>> b
[[1, 2, [999, 6]], [4, 5, 6]]

Run Code Online (Sandbox Code Playgroud)

经过copy()

您会发现该功能与和copy()相同。它们都是浅拷贝list()[:]

有关浅复制和深复制的更多信息,也许您可​​以参考这里

>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = copy.copy(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
[[1, 10, 3], [4, 5, 6]]

Run Code Online (Sandbox Code Playgroud)

经过deepcopy()

>>> import copy
>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = copy.deepcopy(a)
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0] = 1
>>> a
[1, [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]


>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = copy.deepcopy(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
[[1, 2, 3], [4, 5, 6]]

Run Code Online (Sandbox Code Playgroud)


alj*_*gom 10

如果列表的内容是原始数据类型,则可以使用理解

new_list = [i for i in old_list]
Run Code Online (Sandbox Code Playgroud)

您可以将其嵌套为多维列表,例如:

new_grid = [[i for i in row] for row in grid]
Run Code Online (Sandbox Code Playgroud)

  • 这不是深拷贝。 (2认同)

tai*_*raj 7

如果您list elements是,immutable objects那么您可以使用它,否则您必须使用deepcopyfromcopy模块。

你也可以使用最短的方式进行这样的深拷贝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]
Run Code Online (Sandbox Code Playgroud)

  • 这不是深度复制。 (25认同)
  • 阅读[this](http://docs.python.org/2/library/copy.html),[:]只是创建一个浅拷贝,它不会递归地创建其中对象的副本。 (2认同)
  • 尝试使用嵌套列表。更新列表 a 的嵌套项。它也会在列表 b 中更新。这意味着 [:] 不是深拷贝。 (2认同)
  • [Python 文档](https://docs.python.org/3.7/tutorial/datastructures.html)(请参阅“list.copy()”)明确将“a[:]”描述为执行浅复制的方法。 (2认同)