当切片执行浅拷贝时以及在Python 3中执行深拷贝时

问题描述 投票:0回答:2
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列表

python slice deep-copy shallow-copy
2个回答
4
投票

对于列表和大多数序列类型,切片检索会生成列表切片部分的浅表副本。在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数组)会返回原始对象数据的视图以进行切片检索,但这比复制的副本更少。


1
投票

从列表的片中分配始终是浅拷贝 - 也就是说,它复制源列表中的引用。

当您分配一个列表(无论是通过复制还是其他任何方法创建)时,您不会改变引用的对象 - 您正在更改列表中的引用,所以现在它指向其他内容。这就是你的第一个例子:

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]相同列表的引用,因此无论您使用哪个引用来获取它,变异调用都会影响它。

© www.soinside.com 2019 - 2024. All rights reserved.