Python copy
模块实用教程
目录
Python中的copy
模块提供了对象拷贝的功能,主要包含两种拷贝方式:浅拷贝(shallow copy)和深拷贝(deep copy)。
import copy # 使用前需要导入copy模块
1.浅拷贝(Shallow Copy)
浅拷贝创建一个新对象,但它不会递归地创建子对象的副本,而是只复制子对象的引用。
使用对象自带copy()
方法
许多内置容器类型(list, dict等)提供了copy()
方法实现浅拷贝:
original_list = [1, 2, [3, 4]]
shallow_copied_list = original_list.copy()
print(shallow_copied_list) # [1, 2, [3, 4]]
# 修改原始列表中的可变元素会影响浅拷贝的列表
original_list[2][0] = 'changed'
print(shallow_copied_list) # [1, 2, ['changed', 4]]
使用copy.copy()
函数
copy
模块提供的通用浅拷贝函数:
import copy
original_dict = {'a': 1, 'b': [2, 3]}
shallow_copied_dict = copy.copy(original_dict)
original_dict['b'][0] = 'changed'
print(shallow_copied_dict) # {'a': 1, 'b': ['changed', 3]}
使用切片操作
对于序列类型(list, tuple等),切片操作可以创建浅拷贝:
original = [1, 2, [3, 4]]
shallow_copy = original[:]
original[2][1] = 'changed'
print(shallow_copy) # [1, 2, [3, 'changed']]
使用工厂函数
使用类型构造函数创建浅拷贝:
original = [1, 2, [3, 4]]
shallow_copy = list(original)
original[0] = 'changed'
print(shallow_copy) # [1, 2, [3, 4]] - 第一层不受影响
original[2][0] = 'changed'
print(shallow_copy) # [1, 2, ['changed', 4]] - 第二层受影响
2.深拷贝(Deep Copy)
深拷贝创建一个新对象,并递归地复制所有子对象,因此新对象和原始对象完全独立。
使用copy.deepcopy()
函数
import copy
original = [1, 2, [3, 4]]
deep_copied = copy.deepcopy(original)
original[2][0] = 'changed'
print(original) # [1, 2, ['changed', 4]]
print(deep_copied) # [1, 2, [3, 4]] - 不受影响
深拷贝会处理所有子对象,包括列表、字典、自定义对象等:
original = {'a': [1, 2], 'b': {'c': 3}}
deep_copied = copy.deepcopy(original)
original['a'][0] = 'changed'
original['b']['c'] = 'changed'
print(deep_copied) # {'a': [1, 2], 'b': {'c': 3}} - 完全不受影响
3.浅拷贝与深拷贝的区别
原理分析
-
浅拷贝:
- 只复制对象本身,不复制它引用的子对象
- 新对象和原对象共享子对象的引用
- 对于可变子对象,修改会影响所有副本
-
深拷贝:
- 递归复制对象及其所有子对象
- 新对象和原对象完全独立
- 修改任何一方都不会影响另一方
可视化比较
浅拷贝示例:
Original [1, 2, [3, 4]] Shallow Copy [1, 2, [3, 4]]
| |
+---------> [3, 4] <-------+
深拷贝示例:
Original [1, 2, [3, 4]] Deep Copy [1, 2, [3, 4]]
| |
+-> [3, 4] +-> [3, 4] (新的独立列表)
使用情景
使用浅拷贝的情况:
- 对象只包含原始数据类型或不可变对象
- 需要共享子对象引用以节省内存
- 明确知道子对象不会被修改
使用深拷贝的情况:
- 对象包含嵌套的可变对象
- 需要完全独立的副本
- 不确定子对象是否会被修改
4.特殊对象的拷贝行为
自定义对象的拷贝
自定义类可以通过定义__copy__()
和__deepcopy__()
方法来控制拷贝行为:
class MyClass:
def __init__(self, x, y):
self.x = x
self.y = y
self.nested = [1, 2, 3]
def __copy__(self):
print("执行浅拷贝")
new_obj = MyClass(self.x, self.y)
new_obj.nested = self.nested # 共享nested引用
return new_obj
def __deepcopy__(self, memo):
print("执行深拷贝")
new_obj = MyClass(self.x, self.y)
new_obj.nested = copy.deepcopy(self.nested, memo) # 创建nested的副本
return new_obj
obj = MyClass(5, 10)
shallow_obj = copy.copy(obj)
deep_obj = copy.deepcopy(obj)
obj.nested[0] = 'changed'
print(shallow_obj.nested) # ['changed', 2, 3]
print(deep_obj.nested) # [1, 2, 3]
不可变对象的拷贝
对于不可变对象(如整数、字符串、元组等),拷贝通常不会创建新对象,而是返回原对象的引用:
a = "hello"
b = copy.copy(a)
c = copy.deepcopy(a)
print(a is b is c) # True,所有都是同一个对象
# 但对于包含可变元素的元组,深拷贝会有不同行为
t = (1, [2, 3])
t_copy = copy.copy(t)
t_deepcopy = copy.deepcopy(t)
print(t[1] is t_copy[1]) # True,浅拷贝共享列表引用
print(t[1] is t_deepcopy[1]) # False,深拷贝创建了新列表
5.拷贝性能
-
浅拷贝:
- 速度快
- 内存消耗少
- 时间复杂度一般为O(n),n为顶层元素数量
-
深拷贝:
- 速度慢,特别是对于复杂对象结构
- 内存消耗大
- 时间复杂度一般为O(n+m),n为对象数量,m为引用数量
- 使用memo字典避免无限递归和重复拷贝
对于大型数据结构,深拷贝可能会很昂贵:
import time
large_list = [[i for i in range(1000)] for _ in range(1000)]
start = time.time()
shallow_copy = copy.copy(large_list)
print(f"浅拷贝时间: {time.time() - start:.4f}秒")
start = time.time()
deep_copy = copy.deepcopy(large_list)
print(f"深拷贝时间: {time.time() - start:.4f}秒")
6.注意事项
-
意外共享可变状态:
# 错误示例 config = {'param': [1, 2, 3]} default_config = config.copy() # 浅拷贝 config['param'][0] = 'changed' print(default_config) # {'param': ['changed', 2, 3]} # 正确做法 default_config = copy.deepcopy(config)
-
循环引用处理:
a = [1, 2] b = [a, 3] a.append(b) # 创建循环引用 # deepcopy能正确处理循环引用 a_copy = copy.deepcopy(a)
-
自定义对象的特殊拷贝需求:
class DatabaseConnection: def __init__(self, connection_string): self.connection_string = connection_string self.connection = connect(connection_string) def __deepcopy__(self, memo): # 数据库连接不应该被复制,而是应该重新建立 new_obj = DatabaseConnection(copy.deepcopy(self.connection_string, memo)) return new_obj
-
不可变对象的冗余拷贝:
# 不必要的深拷贝 immutable_tuple = (1, 2, 3) copied = copy.deepcopy(immutable_tuple) # 浪费资源
总结
- 浅拷贝创建新对象但共享子对象引用,适用于简单对象或需要共享状态的情况
- 深拷贝创建完全独立的对象副本,适用于复杂嵌套结构或需要隔离状态的情况
- 自定义类可以通过实现
__copy__
和__deepcopy__
方法来控制拷贝行为 - 不可变对象通常不需要也不应该被深拷贝
- 深拷贝比浅拷贝更消耗资源,应谨慎使用
- 注意避免由意外共享可变状态引起的bug