Python __deepcopy__ 方法
最后修改于 2025 年 4 月 8 日
本综合指南探讨了 Python 的 __deepcopy__ 方法,这是一种特殊方法,可以为对象启用自定义的深拷贝行为。我们将介绍基本用法、实现模式和实际示例。
基本定义
__deepcopy__ 方法由 copy.deepcopy() 调用,用于实现深拷贝操作。它必须定义如何创建对象的深拷贝,包括所有嵌套对象。
主要特征:它接受一个备忘录字典来处理循环引用,返回对象的一个新的独立副本,并且应该递归地深拷贝所有可变属性。它提供了对深拷贝过程的完全控制。
基本 __deepcopy__ 实现
这是一个简单的实现,展示了 __deepcopy__ 如何与 copy 模块一起工作。它演示了基本结构和备忘录用法。
import copy
class Box:
def __init__(self, items):
self.items = items
def __deepcopy__(self, memo):
print("Performing deep copy of Box")
new_items = copy.deepcopy(self.items, memo)
new_box = Box(new_items)
memo[id(self)] = new_box
return new_box
original = Box([[1, 2], [3, 4]])
copied = copy.deepcopy(original)
print(copied.items)
这个例子展示了一个带有嵌套列表的 Box 类。__deepcopy__ 方法创建了一个新的 Box,其中包含其项目的深拷贝。备忘录字典有助于防止循环引用的无限递归。
该方法首先创建项目的深拷贝,然后使用这些拷贝的项目创建一个新的 Box 实例。原始对象和拷贝对象是完全独立的。
处理循环引用
__deepcopy__ 中的备忘录字典通过跟踪已经拷贝的对象来帮助处理循环引用。 这可以防止无限递归。
import copy
class Node:
def __init__(self, value):
self.value = value
self.next = None
def __deepcopy__(self, memo):
if id(self) in memo:
return memo[id(self)]
print(f"Copying node {self.value}")
new_node = Node(copy.deepcopy(self.value, memo))
memo[id(self)] = new_node
new_node.next = copy.deepcopy(self.next, memo)
return new_node
# Create circular reference
node1 = Node(1)
node2 = Node(2)
node1.next = node2
node2.next = node1
copied = copy.deepcopy(node1)
print(copied.next.next.value) # 1
这个 Node 类形成了一个循环引用。 __deepcopy__ 方法在拷贝之前检查备忘录字典,以正确处理循环引用。 如果没有此检查,它将无限递归。
备忘录通过对象的 id 存储已经拷贝的对象。 当遇到已经拷贝的节点时,它返回存储的副本而不是递归。
自定义深拷贝行为
__deepcopy__ 允许自定义如何拷贝特定属性,这在某些属性不应被深拷贝时非常有用。
import copy
class Config:
def __init__(self, params, logger):
self.params = params
self.logger = logger # Should not be deep copied
def __deepcopy__(self, memo):
print("Creating custom deep copy of Config")
new_params = copy.deepcopy(self.params, memo)
new_config = Config(new_params, self.logger)
memo[id(self)] = new_config
return new_config
logger = object()
original = Config({"timeout": 30, "retries": 3}, logger)
copied = copy.deepcopy(original)
print(copied.params)
print(copied.logger is original.logger) # True
这个 Config 类演示了选择性的深拷贝。 params 字典被深拷贝,但 logger 引用在原始对象和拷贝对象之间共享。
当某些属性表示不应在拷贝操作期间复制的共享资源或单例时,此模式非常有用。
带有继承的深拷贝
在继承层次结构中实现 __deepcopy__ 时,您需要正确处理父类属性和备忘录字典。
import copy
class Base:
def __init__(self, base_value):
self.base_value = base_value
def __deepcopy__(self, memo):
print("Deep copying Base")
new_base = self.__class__(copy.deepcopy(self.base_value, memo))
memo[id(self)] = new_base
return new_base
class Derived(Base):
def __init__(self, base_value, derived_value):
super().__init__(base_value)
self.derived_value = derived_value
def __deepcopy__(self, memo):
print("Deep copying Derived")
new_obj = super().__deepcopy__(memo)
new_obj.derived_value = copy.deepcopy(self.derived_value, memo)
return new_obj
original = Derived([1, 2], {"a": 1})
copied = copy.deepcopy(original)
print(copied.base_value, copied.derived_value)
这个例子展示了带有继承的正确的 __deepcopy__ 实现。 Derived 类首先委托给父类的 __deepcopy__,然后处理自己的属性。
备忘录字典通过整个拷贝过程传递,以保持继承层次结构中的一致性并处理潜在的循环引用。
性能优化
可以通过避免不必要的不可变对象拷贝或为复杂结构实现自定义拷贝逻辑来优化 __deepcopy__。
import copy
class LargeData:
def __init__(self, data, metadata):
self.data = data # Large, complex structure
self.metadata = metadata # Small, simple structure
def __deepcopy__(self, memo):
print("Optimized deep copy of LargeData")
# Skip deep copying metadata as it's small and contains only immutables
new_metadata = self.metadata
# Custom optimized copy for large data
new_data = [copy.deepcopy(item, memo) for item in self.data]
new_obj = self.__class__(new_data, new_metadata)
memo[id(self)] = new_obj
return new_obj
original = LargeData([[1, 2, 3]] * 1000, {"created": "2025-01-01"})
copied = copy.deepcopy(original)
print(len(copied.data), copied.metadata)
这种优化后的实现避免了对元数据字典的深拷贝,因为它只包含不可变值。 它还为大型数据结构使用列表推导式,以使拷贝过程更加高效。
在处理标准深拷贝过于缓慢或内存密集的大型对象时,这种优化非常有价值。
最佳实践
- 始终使用备忘录字典:对于处理循环引用至关重要
- 拷贝所有可变属性:确保拷贝的完全独立性
- 保留对象标识:在递归拷贝之前将新对象添加到备忘录
- 考虑不可变对象:跳过不可变对象的拷贝以提高性能
- 记录行为:清楚地记录任何自定义拷贝行为
资料来源
作者
列出所有 Python 教程。