【问题标题】:When the slice do shallow copy and when it do deep copy in Python 3当切片在 Python 3 中进行浅拷贝和深拷贝时
【发布时间】:2019-02-28 18:56:20
【问题描述】:
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],它不会影响原来的bs列表,它仍然是[1,2,3]

【问题讨论】:

  • ID 值仅保证对于具有重叠生命周期的对象是不同的。 id 对于 Python 的新学习者来说几乎毫无用处,因为从结果中提取任何有用的含义都需要高水平的理解。
  • 列出切片总是创建浅拷贝。是什么让你觉得“似乎 bs[:] 对 xs 做了深拷贝”???

标签: python slice deep-copy shallow-copy


【解决方案1】:

对于列表和大多数序列类型,切片检索会生成列表切片部分的浅表副本。在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 以进行切片检索,但这比浅拷贝还少。

【讨论】:

    【解决方案2】:

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

    当您分配给列表时(无论它是通过复制还是任何其他方法创建的),您并没有改变引用的对象 - 您正在更改列表中的引用,所以现在它指向其他东西。这就是您在此处的第一个示例中发生的情况:

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

    【讨论】:

      猜你喜欢
      • 2015-01-13
      • 2012-04-12
      • 1970-01-01
      • 1970-01-01
      • 2012-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多