深度复制与列表理解

Deep copy vs. List Comprehension

我对编程比较陌生,我一直在理解一些东西,这似乎是 Python 中克隆对象的基础知识。

假设我们有以下代码但没有使用 deepcopy 模块:

nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
copy = [x for x in nested_list]

现在如果我们做类似的事情:

copy[1] = [9999999]

然后它将return以下内容:

nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
copy = [[1, 2, 3], [9999999], [7, 8, 9]]

但是,如果我们只修改其中一个嵌套列表中的单个元素,例如:

copy[0][1] = 9999999

那么原始变量和副本变量都会return相同的值:

nested_list = [[1, 9999999, 3], [4, 5, 6], [7, 8, 9]]
copy = [[1, 9999999, 3], [4, 5, 6], [7, 8, 9]]

为什么当我们给嵌套列表一个新值时它工作得很好,但是当我们给嵌套列表中的一个项目一个新值时,它也会改变原来的值?在变量 nested_listcopy 上调用 id() 函数表明它们是独立的对象,至少从我的理解来看是这样。

例如:

copy = nested_list                # copy and nested_list share the same id()
copy = [x for x in nested_list]   # now they have different id()
copy = deepcopy(nested_list)      # again they have different id()

我知道另一种解决方案是深度复制功能,但是由于它非常慢,我想知道是否还有其他解决方案?

在此先感谢大家!

copy = [x for x in nested_list] 发生的灰黄色副本正在创建一个新的副本对象,其 id()nested_list 不同,但其中的所有嵌套列表都具有相同的 id两个列表中的列表。

nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
copy = [x for x in nested_list]
print(id(copy)) #54769064
print(id(nested_list)) #54546184
print([id(i) for i in copy]) #[58832096, 58831816, 58619384]
print([id(i) for i in nested_list]) #[58832096, 58831816, 58619384]

进行深度复制时 copy = deepcopy(nested_list) 复制嵌套列表,同时创建具有新 ID 的新列表,当将新值分配给其中一个嵌套列表时,如 copy[0][1] = 9999999 将仅更改复制第一个列表项目而不是 nested_list[0][1] 值。

nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
copy = deepcopy(nested_list)
copy[0][1] = 9999999
print(copy) #[[1, 9999999, 3], [4, 5, 6], [7, 8, 9]]
print(nested_list) #[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

copynested_list 的子列表在内存中的相同位置。并且所有相应的子列表都具有相同的 id。这就是为什么你有这种行为。

nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
copy = [x for x in nested_list]
print(id(copy[0]) == id(nested_list[0])) #True
print(id(copy) == id(nested_list)) #False

如果您提前知道要更改的sublists,那么可以只对该子列表进行深度复制,以加快性能。

我不知道您使用的是哪种编程语言,但变量引用在 python 中的工作方式不同。我建议您阅读这篇清楚说明的文章。 https://www.python-course.eu/python3_deep_copy.php

我还写了一篇关于变量引用的Medium post。你可以看看。

基本上,当你有一个列表列表时会发生什么,然后做

copy[1] = [9999999]

实际上是在更改第一级引用。但是当你像

这样深入时
copy[0][1] = 9999999

那么您正在比尚未复制的参考更深层次地更改元素。把它想象成一棵树。复制功能就像一个浅拷贝,当你执行浅拷贝时,你只是复制并制作另一个第一个引用的对象。但是第2、第3以后还是一样。