当切片在Python 3中进行浅表复制以及何时进行深表复制

时间:2019-02-28 18:56:21

标签: python slice deep-copy shallow-copy

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的原始列表。

2 个答案:

答案 0 :(得分:4)

对于列表和大多数序列类型,切片检索可对列表的切片部分进行浅表复制。在xs = bs[:]中,xs成为bs

的副本 另一方面,切片赋值不会复制切片部分。在bs[:] = [4, 5, 6]中,没有复制bs的任何部分。 [4, 5, 6]的内容直接分配到bs中。 (这些内容是对int对象的引用,引用是被复制的内容-我们不会对任何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数组)会返回原始对象数据的 view 以进行切片检索,但它的拷贝数比浅拷贝数少。

答案 1 :(得分: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]相同列表的引用,因此无论您使用哪个引用来获取它,变异调用都会对其产生影响。