我试图使用拼接运算符制作二维数组的副本。凭直觉,感觉就像我这样做:
L = [[5,6],[7,8]]
M = L[:][:]
然后M
将是L
中每个 nested 元素的克隆副本。因此,我可以更改M[0]
中的项目而无需更改L
:
M[1] = [3,4]
M[0][1] = 2
但是当我这样做时:
print(L)
#returns [[5,2],8]]
当我执行[:][:]
操作时,Python内存中实际上发生了什么?
只需在操作符[:]
的左侧复制列表即可。
[:][:]
进行copy of copy
。您可以执行M = L[:][:][:][:][:][:][:][:][:][:][:][:][:][:]
,它的工作方式相同:D
要同时复制嵌套列表,您应该像M = [x[:] for x in L[:]]
那么M将是L中每个嵌套元素的克隆副本。这是不正确的,因为L[:][:]
与(L[:])[:]
相同,它是原始列表副本的副本。
M[1] = [3,4]
在这里,您修改了COPY
的第二项。
但是在M[0][1] = 2
处,您正在修改原始嵌套数组的项,因为[:]
对嵌套列表不执行任何复制操作,并且复制的原始列表项不是“简单”。 >
警告!!在Python中,当它是列表并执行x = y
时,更改y
中的值会更改x
。
这不是按值复制,而是按引用复制。例如。
>>> x = [[1,2],[3,4]]
>>> y = x
>>> y[0][1] = 5
>>> x
[[1,5],4]]
但是使用x = y[:]
进行复制的方式是正确的。并且[:]
的链接是多余的。
首先让我们了解如何真正为该嵌套列表“按值复制”。为此,通常可以使用copy
模块。
>>> import copy
>>> x = [[1,4]]
>>> y = copy.deepcopy(x)
>>> y[0][1] = 5
>>> x
[[1,4]]
>>> y
[[1,4]]
在https://docs.python.org/3/faq/programming.html#how-do-i-copy-an-object-in-python中,执行y = x[:]
与使用copy.copy相同
现在回到[:]
表示法。如果我们深入探讨嵌套类型,
>>> x = [[1,4]]
>>> type(x)
<class 'list'>
>>> type(x[0])
<class 'list'>
>>> type(x[:])
<class 'list'>
>>> type(x[:][0])
<class 'list'>
>>> type(x[:][0][0])
<class 'int'>
>>> type(x[:][0][0][0])
Traceback (most recent call last):
File "<stdin>",line 1,in <module>
TypeError: 'int' object is not subscriptable
我们看到,如果我们直接在某个点上评估内部列表中的值,则整数值不是列表,因此无法从中获取索引。
继续执行x[:][:][:][:][:]
会发生什么,我们看到它检查出它允许我们继续访问列表,但是当我们执行{{ 1}}?
[:]
在这里,我们看到类型没有改变,如果我们查看实际值,是否开始复制它:
>>> type(x[:][:][:])
<class 'list'>
>>> type(x[:][:][:][:][:])
<class 'list'>
>>> type(x[:][:][:][:][:][:])
<class 'list'>
基本上,您是在第一个>>> x = [[1,4]]
>>> y = copy.deepcopy(x)
>>> y
[[1,4]]
>>> y = copy.deepcopy(x[:])
>>> y
[[1,4]]
>>> y = copy.deepcopy(x[:][:])
>>> y
[[1,4]]
>>> y = copy.deepcopy(x[:][:][:])
>>> y
[[1,4]]
>>> y = copy.deepcopy(x[:][:][:][:])
>>> y
[[1,4]]
处访问完整列表,然后x[:]
的连续链接并不完全是在访问/遍历嵌套循环,而是只需重新复制复制的列表。
将[:]
视为:
z=x[:][:]
现在是阅读切片的文档/问题的好时机
要进行更深入的研究,您必须进入实现。 https://github.com/python/cpython/blob/master/Objects/sliceobject.c