Python copy模块实用教程

Python copy模块实用教程

目录

  1. 浅拷贝(Shallow Copy)
  2. 深拷贝(Deep Copy)
  3. 浅拷贝与深拷贝的区别
  4. 特殊对象的拷贝行为
  5. 拷贝考虑
  6. 注意事项
  7. 总结

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.注意事项

  1. 意外共享可变状态

    # 错误示例
    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)
    
  2. 循环引用处理

    a = [1, 2]
    b = [a, 3]
    a.append(b)  # 创建循环引用
    
    # deepcopy能正确处理循环引用
    a_copy = copy.deepcopy(a)
    
  3. 自定义对象的特殊拷贝需求

    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
    
  4. 不可变对象的冗余拷贝

    # 不必要的深拷贝
    immutable_tuple = (1, 2, 3)
    copied = copy.deepcopy(immutable_tuple)  # 浪费资源
    

总结

  • 浅拷贝创建新对象但共享子对象引用,适用于简单对象或需要共享状态的情况
  • 深拷贝创建完全独立的对象副本,适用于复杂嵌套结构或需要隔离状态的情况
  • 自定义类可以通过实现__copy____deepcopy__方法来控制拷贝行为
  • 不可变对象通常不需要也不应该被深拷贝
  • 深拷贝比浅拷贝更消耗资源,应谨慎使用
  • 注意避免由意外共享可变状态引起的bug

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值