Python __copy__ 方法
最后修改于 2025 年 4 月 8 日
这个全面的指南探讨了 Python 的 __copy__
方法,这是一个控制浅拷贝行为的特殊方法。我们将介绍基本用法、自定义实现和实际示例。
基本定义
__copy__
方法定义了当调用 copy.copy()
函数时,对象应该如何被复制。它返回对象的浅拷贝。
关键特征:它不接受任何参数(除了 self),应该返回一个新对象,并且由 copy.copy()
调用。对于深拷贝,请改用实现 __deepcopy__
。
基本的 __copy__ 实现
这是一个简单的实现,展示了 __copy__
如何与基本对象一起工作。它演示了默认行为和自定义。
import copy class Box: def __init__(self, width, height): self.width = width self.height = height def __copy__(self): print("__copy__ called") return Box(self.width, self.height) def __repr__(self): return f"Box({self.width}, {self.height})" original = Box(10, 20) copy_obj = copy.copy(original) print(copy_obj)
这个例子展示了一个基本的 __copy__
实现。当 copy.copy()
被调用时,它会调用 __copy__
,后者创建一个具有相同尺寸的新 Box。
输出将显示“__copy__ called”并打印复制的 Box。 两个对象都是独立的实例,具有相同的属性值。
浅拷贝 vs 深拷贝
这个例子演示了在处理嵌套对象时浅拷贝和深拷贝之间的区别,以及 __copy__
的作用。
import copy class Container: def __init__(self, items): self.items = items def __copy__(self): print("Shallow copy") return Container(self.items) def __deepcopy__(self, memo): print("Deep copy") return Container(copy.deepcopy(self.items, memo)) original = Container([[1, 2], [3, 4]]) shallow = copy.copy(original) deep = copy.deepcopy(original) original.items[0][0] = 99 print("Shallow:", shallow.items) # Affected by change print("Deep:", deep.items) # Unaffected
这个例子展示了浅拷贝如何共享对嵌套对象的引用,而深拷贝则创建完全独立的副本。__copy__
方法处理浅拷贝的情况。
在修改原始嵌套列表后,浅拷贝反映了更改,而深拷贝保持不变。 这演示了引用共享。
自定义复制行为
可以自定义 __copy__
来精确控制复制的内容和方式。此示例显示了选择性属性复制。
import copy class Account: def __init__(self, balance, transactions): self.balance = balance self.transactions = transactions self.last_access = None def __copy__(self): print("Creating account copy") new_account = Account(self.balance, self.transactions.copy()) new_account.last_access = "Copied from original" return new_account original = Account(1000, ["deposit 500", "withdraw 200"]) copy_acc = copy.copy(original) original.balance = 1500 original.transactions.append("withdraw 300") print("Original:", original.balance, original.transactions) print("Copy:", copy_acc.balance, copy_acc.transactions) print("Copy access:", copy_acc.last_access)
这个 Account 类实现了自定义的复制行为。 balance 被原样复制,transactions 获得浅拷贝,last_access 获得一个特殊值。
对原始 balance 的更改不会影响副本(原始类型),但如果没有在 __copy__
中显式调用 copy()
,事务列表更改将影响副本。
复制不可变对象
对于不可变对象,由于对象无法修改,__copy__
通常可以只返回 self。此示例演示了此优化。
import copy class ImmutablePoint: def __init__(self, x, y): self._x = x self._y = y @property def x(self): return self._x @property def y(self): return self._y def __copy__(self): print("Immutable copy") return self # Safe because object is immutable def __repr__(self): return f"Point({self.x}, {self.y})" point = ImmutablePoint(3, 4) point_copy = copy.copy(point) print(point is point_copy) # True, same object
这个不可变的 point 类从 __copy__
返回自身,因为它的状态无法更改。这对于不可变对象是安全有效的。
is
检查确认两个变量都引用同一个对象。 这种优化避免了为不可变类型创建不必要的对象。
将 __copy__ 与 __deepcopy__ 结合使用
这个例子展示了一个类同时实现复制方法,以适当地处理不同的复制场景。
import copy class Node: def __init__(self, value, children=None): self.value = value self.children = children if children is not None else [] def __copy__(self): print("Shallow copying Node") return Node(self.value, self.children) def __deepcopy__(self, memo): print("Deep copying Node") return Node(copy.deepcopy(self.value, memo), [copy.deepcopy(child, memo) for child in self.children]) root = Node(1, [Node(2), Node(3)]) shallow_root = copy.copy(root) deep_root = copy.deepcopy(root) root.children.append(Node(4)) print("Original children count:", len(root.children)) print("Shallow copy children count:", len(shallow_root.children)) print("Deep copy children count:", len(deep_root.children))
这个 Node 类实现了两种复制方法。 浅拷贝共享子引用,而深拷贝创建完整的独立树结构。
在向原始对象添加子对象后,浅拷贝反映了此更改(共享引用),而深拷贝保持其原始结构。
最佳实践
- 实现两种方法: 在需要时提供
__copy__
和__deepcopy__
- 记录行为: 清楚地记录您的复制语义
- 处理所有属性: 确保复制所有相关的属性
- 考虑不变性: 对于真正不变的对象,返回 self
- 使用 copy 模块: 在实现中利用
copy
和deepcopy
资料来源
作者
列出所有 Python 教程。