bs = [1, 2, 3]
print(id(bs))
print(id(bs[:]))
xs = bs[:]
xs[1] = [9, 9, 9]
print(bs)
print(xs)
-------------
4452573000
4452573064
[1, 2, 3]
[1, [9, 9, 9], 3]
似乎bs[:]
对xs
做了深刻的复制
bs = [1, 2, 3]
print(id(bs))
print(id(bs[:]))
xs = bs[:] = [4, 5, 6]
print(id(xs))
print(bs)
print(xs)
----------
4518600520
4518600584
4518600584
[4, 5, 6]
[4, 5, 6]
似乎bs[:]
做了xs
的浅拷贝
bs[:] = [4, 5, 6]
将把bs
的原始列表修改为[4, 5, 6]
。但如果只做xs = bs[:]
和xs[1] = [9, 9, 9]
,它不会影响仍然[1,2,3]
的原始bs列表
对于列表和大多数序列类型,切片检索会生成列表切片部分的浅表副本。在xs = bs[:]
,xs
成为bs
的副本
另一方面,切片分配不会复制切片部分。在bs[:] = [4, 5, 6]
,没有复制bs
的任何部分。 [4, 5, 6]
的内容直接分配到bs
。 (这些内容是对int对象的引用,引用是复制的 - 我们不会改变任何整数。)
在链式赋值xs = bs[:] = [4, 5, 6]
中,分配给xs
的值是由右侧的[4, 5, 6]
表达式生成的列表,而不是bs
的切片。赋值执行为
temp = [4, 5, 6]
xs = temp
bs[:] = temp
不是
bs[:] = [4, 5, 6]
xs = bs[:]
没有执行切片检索,也没有制作bs
的副本。
我不知道Python语言核心,Python标准库或任何常用的第三方库中的单一类型,其中切片执行深层复制。某些类型(如memoryviews和NumPy数组)会返回原始对象数据的视图以进行切片检索,但这比复制的副本更少。
从列表的片中分配始终是浅拷贝 - 也就是说,它复制源列表中的引用。
当您分配一个列表(无论是通过复制还是其他任何方法创建)时,您不会改变引用的对象 - 您正在更改列表中的引用,所以现在它指向其他内容。这就是你的第一个例子:
xs[1] = [9, 9, 9]
这会将xs[1]
更改为对新的[9, 9, 9
列表的引用。 xs
内容的来源无关紧要。
这可能很重要的是,如果你有一个可变对象的列表,并且你在它们上使用变异方法而不是重新分配:
bs = [[1], [2], [3]]
xs = bs[:] # now xs is a shallow copy of bs - it contains references to the same objects
xs[1].append(4)
在这里,xs[1]
是与bs[1]
相同列表的引用,因此无论您使用哪个引用来获取它,变异调用都会影响它。