copy — 浅层和深层复制操作

源代码: Lib/copy.py


Python 中的赋值语句不会复制对象,它们会在目标和对象之间创建绑定。对于可变或包含可变项的集合,有时需要复制,以便可以更改一个副本而不更改另一个副本。此模块提供通用的浅层和深层复制操作(如下所述)。

接口摘要

copy.copy(obj)

返回 obj 的浅层副本。

copy.deepcopy(obj[, memo])

返回 obj 的深层副本。

copy.replace(obj, /, **changes)

创建一个与 obj 类型相同的新对象,并用 changes 中的值替换字段。

3.13 版本新增。

exception copy.Error

为模块特定错误引发。

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

  • 浅层复制 构造一个新的复合对象,然后(在可能的范围内)将引用插入到原始对象中找到的对象中。

  • 深层复制 构造一个新的复合对象,然后递归地将原始对象中找到的对象的副本插入到其中。

深层复制操作通常存在两个浅层复制操作不存在的问题

  • 递归对象(直接或间接包含对其自身的引用的复合对象)可能会导致递归循环。

  • 因为深层复制会复制所有内容,所以它可能会复制太多,例如打算在副本之间共享的数据。

deepcopy() 函数通过以下方式避免这些问题:

  • 保留一个 memo 字典,其中包含当前复制过程中已复制的对象;并且

  • 允许用户定义的类重写复制操作或复制的组件集。

此模块不复制模块、方法、堆栈跟踪、堆栈帧、文件、套接字、窗口或任何类似类型。它通过返回未更改的原始对象来“复制”函数和类(浅层和深层);这与 pickle 模块处理这些对象的方式兼容。

可以使用 dict.copy() 进行字典的浅层复制,使用整个列表的切片进行列表的浅层复制,例如,copied_list = original_list[:]

类可以使用相同的接口来控制复制,这些接口用于控制 pickling。有关这些方法的信息,请参阅模块 pickle 的描述。实际上,copy 模块使用 copyreg 模块中注册的 pickle 函数。

为了让类定义自己的复制实现,它可以定义特殊方法 __copy__()__deepcopy__()

object.__copy__(self)

调用以实现浅层复制操作;不传递其他参数。

object.__deepcopy__(self, memo)

调用以实现深层复制操作;它传递一个参数,即 memo 字典。如果 __deepcopy__ 实现需要对组件进行深层复制,则应将组件作为第一个参数,将 memo 字典作为第二个参数来调用 deepcopy() 函数。memo 字典应被视为不透明对象。

函数 copy.replace()copy()deepcopy() 的功能更有限,仅支持由 namedtuple()dataclasses 和其他定义方法 __replace__() 的类创建的命名元组。

object.__replace__(self, /, **changes)

此方法应创建一个相同类型的新对象,并用 changes 中的值替换字段。

另请参阅

模块 pickle

关于用于支持对象状态检索和恢复的特殊方法的讨论。