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 教程。