【问题标题】:List slicing vs copying [duplicate]列表切片与复制[重复]
【发布时间】:2021-09-07 10:30:13
【问题描述】:

python copy 的行为与 L[:] 的行为相同还是 L[:] 的行为更像 deepcopy 或其他?只是一个基本的例子:

from copy import copy
L = [1,2,3]
L[:]
# [1,2,3]
copy(L)
# [1,2,3]

【问题讨论】:

  • 这不是一个非常有用的例子,因为整数是不可变的——无论如何你都无法区分深拷贝和浅拷贝。

标签: python


【解决方案1】:

L.copy()L[:] 工作方式相同 - 都是浅拷贝。起初只有L[:] 存在; .copy() 是后来添加的,因此需要副本的通用代码可以以不规范的方式拼写(dict.copy()set.copy()、...)。

示例

>>> L = [[1, 2], [3, 4]]
>>> L1 = L[:]
>>> [a is b for a, b in zip(L, L1)]
[True, True]
>>> L1 = L.copy()
>>> [a is b for a, b in zip(L, L1)]
[True, True]
>>> import copy
>>> L1 = copy.copy(L)
>>> [a is b for a, b in zip(L, L1)]
[True, True]
>>> L1 = copy.deepcopy(L) # this one differs!
>>> [a is b for a, b in zip(L, L1)]
[False, False]

【讨论】:

  • 谢谢,为了彻底,只想添加一个简短的例子,说明[:]/copydeepcopy 有何不同?
  • 当然 - 添加了 4 种复制方式的示例。
【解决方案2】:

它很复杂。对象自己决定切片的含义。 L[1:3] 变成了对魔术方法 L.__getitem__(slice(1,3)) 的调用,对象决定它应该如何处理。 list 会做一个浅拷贝。

其他对象会做不同的事情。例如,范围对象为您提供了一个新的范围对象。

>>> range(5)[:3]
range(0, 3)

对执行大量元编程并变得更加复杂的包进行切片。

【讨论】:

  • 确实如此,但问题标题仅专门询问“列表切片与复制”。
【解决方案3】:

补充 Tim Peters 的答案。来自copy 模块文档:

可以使用dict.copy() 制作字典的浅拷贝,并通过分配整个列表的一个切片来制作列表,例如copied_list = original_list[:]

另外,为了解决 Tim Peters 回答下方的评论,关于 copydeepcopy 之间的区别:

浅拷贝和深拷贝之间的区别仅与复合对象(包含其他对象的对象,如列表或类实例)有关:

  • 浅拷贝构造一个新的复合对象,然后(在可能的范围内)向其中插入对原始对象的引用。
  • 深拷贝构造一个新的复合对象,然后递归地将原始对象的副本插入其中。

例如看以下:

>>> import copy
>>> l1 = [[1,2], 2, 3]
>>> l2 = copy.copy(l1)
>>> l1[0].append(3)
>>> l1
[[1, 2, 3], 2, 3]
>>> l2
[[1, 2, 3], 2, 3]
>>> l3 = copy.deepcopy(l1)
>>> l1[0].append(4)
>>> l1
[[1, 2, 3, 4], 2, 3]
>>> l3
[[1, 2, 3], 2, 3]

l2 与(浅)copy 复制时,第一个条目的引用在l1l2 之间共享。因此,变异l1[0] 也会变异l2[0]。但是在deepcopy (l3) 中,复制是递归完成的,所以l1[0] != l3[0] 和变异一个不会影响另一个。

【讨论】:

    猜你喜欢
    • 2015-05-09
    • 1970-01-01
    • 2023-03-28
    • 2019-06-16
    • 1970-01-01
    • 2011-01-14
    • 2021-07-21
    • 1970-01-01
    • 2016-10-27
    相关资源
    最近更新 更多