如何深度复制列表?
- 2024-12-02 08:41:00
- admin 原创
- 163
问题描述:
之后E0_copy = list(E0)
,我猜测E0_copy
是的深层复制,E0
因为id(E0)
不等于id(E0_copy)
。然后我E0_copy
在循环中修改,但为什么E0
之后不一样了?
E0 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
for k in range(3):
E0_copy = list(E0)
E0_copy[k][k] = 0
#print(E0_copy)
print E0 # -> [[0, 2, 3], [4, 0, 6], [7, 8, 0]]
解决方案 1:
E0_copy
不是深层复制。不能使用 进行深层复制list()
。(list(...)
和testList[:]
都是浅层复制, 也是testList.copy()
。)
您使用它copy.deepcopy(...)
来深度复制列表。
copy.deepcopy(x[, memo])
返回x的深层副本。
请参阅以下代码片段 -
>>> 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]]
解释一下,list(...)
不会递归复制内部对象。它只会复制最外层列表,同时仍引用相同的内部列表,因此,当您改变内部列表时,更改会反映在原始列表和浅层副本中。您可以通过检查 where 来看到浅层复制引用了内部id(a[0]) == id(b[0])
列表b = list(a)
。
解决方案 2:
在 Python 中,有一个名为的模块copy
,它具有两个有用的功能:
import copy
copy.copy()
copy.deepcopy()
copy()
是一个浅拷贝函数。如果给定的参数是一个复合数据结构,例如一个列表,那么 Python 将创建另一个相同类型的对象(在本例中为一个新列表),但对于旧列表中的所有内容,仅复制它们的引用。可以这样想:
newList = [elem for elem in oldlist]
直观地讲,我们可以假设它将deepcopy()
遵循相同的范例,唯一的区别是对于每个元素,我们将递归调用 deepcopy ,(就像mbguy 的答案一样)
但这是错误的!
deepcopy()
实际上保留了原始化合物数据的图形结构:
a = [1,2]
b = [a,a] # there's only 1 object a
c = deepcopy(b)
# check the result
c[0] is a # False, a new object a_1 is created
c[0] is c[1] # True, c is [a_1, a_1] not [a_1, a_2]
这是比较棘手的部分:在过程中deepcopy()
,使用哈希表(Python 中的字典)将每个旧对象引用映射到每个新对象引用,这样可以防止不必要的重复,从而保留复制的复合数据的结构。
官方文档
解决方案 3:
如果列表的内容是原始数据类型,则可以使用理解
new_list = [i for i in old_list]
您可以将其嵌套为多维列表,例如:
new_grid = [[i for i in row] for row in grid]
解决方案 4:
@Sukrit Kalra
第一点:list()
、[:]
、copy.copy()
都是浅拷贝,如果对象是复合的,都不适合,需要用copy.deepcopy()
。
2:b = a
直接,a
和b
有相同的引用,改变a
就等于改变b
。
置 a 为 b
如果直接开始a
,b
并a
共享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]]
卷影复制
经过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]]
经过[:]
>>> 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]]
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]]
经过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]]
经过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]]
解决方案 5:
如果您的列表元素是不可变对象,那么您可以使用它,否则您必须使用deepcopy
模块copy
。
您还可以使用最短路径进行深度复制,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]
解决方案 6:
以下是如何深度复制二维列表的示例:
b = [x[:] for x in a]
解决方案 7:
如果不允许直接导入模块,您可以定义自己的 deepcopy 函数为 -
def copyList(L):
if type(L[0]) != list:
return [i for i in L]
else:
return [copyList(L[i]) for i in range(len(L))]
它的工作原理很容易看出——
>>> x = [[1,2,3],[3,4]]
>>> z = copyList(x)
>>> x
[[1, 2, 3], [3, 4]]
>>> z
[[1, 2, 3], [3, 4]]
>>> id(x)
2095053718720
>>> id(z)
2095053718528
>>> id(x[0])
2095058990144
>>> id(z[0])
2095058992192
>>>
解决方案 8:
如果您使用 deepcopy 分配到同一列表,请改用临时变量。出于某种原因,当尝试使用索引自行更新同一变量时,copy.deepcopy() 不适用于对象列表
S = S[idx] ->x
S = copy.deepcopy(S[idx]) -> x
vvvv 虽然这有效
Stemp = np.zeros(N,dtype=object)
for ii in range(N):
Stemp[ii]=copy.deepcopy(S[idx[ii]])
S= copy.deepcopy(Stemp)
解决方案 9:
只是一个递归深度复制函数。
def deepcopy(A):
rt = []
for elem in A:
if isinstance(elem,list):
rt.append(deepcopy(elem))
else:
rt.append(elem)
return rt
编辑:正如 Cfreak 提到的,这已经在copy
模块中实现。
解决方案 10:
将列表视为一棵树,python 中的 deep_copy 可以最紧凑地写为
def deep_copy(x):
if not isinstance(x, list):
return x
else:
return [deep_copy(elem) for elem in x]
它基本上是以深度优先的方式递归遍历列表。