一维列表与二维列表中的浅拷贝

Shallow copy in 1-D list vs 2-D list

我在 Python 中发现了很多与 "shallow copy" 相关的讨论,但我找不到我的确切问题。

根据我的理解,创建一个浅拷贝仍然包含对列表原始值的引用。这适用于以下二维列表的情况。

>>> x = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> y = list(x)
>>> x.append(['New value'])
>>> x
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['New value']]
>>> y
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> x[0][0] = 'A'
>>> x
[['A', 2, 3], [4, 5, 6], [7, 8, 9], ['New value']]
>>> y
[['A', 2, 3], [4, 5, 6], [7, 8, 9]]

现在,在一维列表中,我没有发现这种效果。

>>> a = [1,2,3,4,5]
>>> b = list(a)
>>> a.append(10)
>>> a
[1, 2, 3, 4, 5, 10]
>>> b
>>> [1, 2, 3, 4, 5]
>>> a[0] = 'A'
>>> a
['A', 2, 3, 4, 5, 10]
>>> b
[1, 2, 3, 4, 5]

谁能解释一下这种差异背后的原因?

列表中的列表是引用,因此它们共享相同的内存space即使您复制外部列表以使其不存在也是如此。请注意,如果您替换嵌套列表中的列表,它只会更改一个列表而不是副本。数字不是引用,因此当您复制列表时,它们不再共享相同的内存 space

浅拷贝 复制顶级项目,为每个项目创建一个新实例。如果有任何复杂元素,浅拷贝将创建这些项目的新副本,但不会创建它们元素的新实例。对嵌套列表的引用将是新的,但二级引用仍将用于原始对象。

深度复制每个 级别创建每个 元素的新实例。一个副作用是这会使该项目占用的存储空间翻倍(现在是两个项目)。

这里可以看到效果特写。浅拷贝,b,每个顶级项目都有自己的副本;当我们更改标量 a[0] 时,b 中的副本不会更改。然后,尽管 b[2]a[2] 的位置不同,但指针值是相同的:它们指向相同的较低级别列表。因此,当我们更改 a[2][1] 时,该更改会反映在 b[2][1].

>>> a = [1, 2, ['a', 'b', 'c'], 4, 5]
>>> b = list(a)
>>> a[0] = "new 1"
>>> a[2][1] = "Deeper"
>>> a
['new 1', 2, ['a', 'Deeper', 'c'], 4, 5]
>>> b
[1, 2, ['a', 'Deeper', 'c'], 4, 5]

用 C 指针思考。您列出的是许多地址,其中包括一个列表。您只是复制整个列表的一个新实例,但如果您修改包含在您的列表中的地址上的内容,将会影响此列表。 你是3个三个list inside x和inside y有相同的地址,但是x和y有不同的地址。

x == 0x0123  #Hexadecimal addresses
y == 0x0456
x = [0x01, 0x02, 0x03, whatever_you_want]
y = [0x01, 0x02, 0x03]
0x01 = [1, 2, 3]

当我们一起分配给列表时,如果你写的不是y = list(x)而是y = x,x和y将同时改变,因为它们将是指向相同地址的指针,比如x = y = 0x0123

我不是很确定,但这是我用 C 的实际知识来理解它的方式