杰瑞科技汇

Python字典如何实现深拷贝?

浅拷贝 vs. 深拷贝

在理解 deepcopy 之前,必须先明白它与 copy()(浅拷贝)的区别,这个区别主要体现在当字典包含可变对象(如列表、字典、集合等)时。

Python字典如何实现深拷贝?-图1
(图片来源网络,侵删)

浅拷贝 (dict.copy()copy.copy())

浅拷贝会创建一个新的字典对象,但是这个新字典中的元素(键值对)是对原字典中元素的引用

  • 对于不可变对象(如数字、字符串、元组):因为它们的内容不能被修改,所以看起来就像是“复制”了。
  • 对于可变对象(如列表、字典):新字典中的可变对象和原字典中的是同一个对象,修改这个可变对象,会同时影响到原字典和拷贝后的字典。

示例代码:

# 原始字典
original_dict = {
    'name': 'Alice',
    'scores': [88, 92, 76],
    'info': {'city': 'New York'}
}
# 使用 .copy() 进行浅拷贝
shallow_copied_dict = original_dict.copy()
# 修改不可变对象 'name'
shallow_copied_dict['name'] = 'Bob'
print(f"Original name: {original_dict['name']}")      # 输出: Original name: Alice
print(f"Copied name: {shallow_copied_dict['name']}")    # 输出: Copied name: Bob
# 不可变对象的修改互不影响,符合预期。
# 修改可变对象 'scores' 中的元素
shallow_copied_dict['scores'].append(100)
print("\nAfter modifying 'scores' list:")
print(f"Original scores: {original_dict['scores']}")  # 输出: Original scores: [88, 92, 76, 100]
print(f"Copied scores: {shallow_copied_dict['scores']}") # 输出: Copied scores: [88, 92, 76, 100]
# 可变对象的修改影响了原字典!这就是浅拷贝的关键。
# 修改嵌套的可变对象 'info'
shallow_copied_dict['info']['city'] = 'Boston'
print("\nAfter modifying nested 'info' dict:")
print(f"Original info: {original_dict['info']}")      # 输出: Original info: {'city': 'Boston'}
print(f"Copied info: {shallow_copied_dict['info']}")    # 输出: Copied info: {'city': 'Boston'}
# 嵌套的可变对象的修改也影响了原字典!

深拷贝 (copy.deepcopy())

深拷贝会创建一个全新的字典对象,并且递归地复制这个字典中所有的可变对象,使得新字典中的所有元素都与原字典完全独立,修改深拷贝后的字典中的任何元素,都不会影响到原字典。

如何使用:

Python字典如何实现深拷贝?-图2
(图片来源网络,侵删)

你需要先导入 copy 模块,然后使用 copy.deepcopy() 函数。

import copy
# 原始字典
original_dict = {
    'name': 'Alice',
    'scores': [88, 92, 76],
    'info': {'city': 'New York'}
}
# 使用 copy.deepcopy() 进行深拷贝
deep_copied_dict = copy.deepcopy(original_dict)
# 修改不可变对象 'name'
deep_copied_dict['name'] = 'Bob'
print(f"Original name: {original_dict['name']}")      # 输出: Original name: Alice
print(f"Copied name: {deep_copied_dict['name']}")    # 输出: Copied name: Bob
# 不可变对象的修改互不影响,符合预期。
# 修改可变对象 'scores' 中的元素
deep_copied_dict['scores'].append(100)
print("\nAfter modifying 'scores' list:")
print(f"Original scores: {original_dict['scores']}")  # 输出: Original scores: [88, 92, 76]
print(f"Copied scores: {deep_copied_dict['scores']}") # 输出: Copied scores: [88, 92, 76, 100]
# 可变对象的修改没有影响原字典!这是深拷贝的核心优势。
# 修改嵌套的可变对象 'info'
deep_copied_dict['info']['city'] = 'Boston'
print("\nAfter modifying nested 'info' dict:")
print(f"Original info: {original_dict['info']}")      # 输出: Original info: {'city': 'New York'}
print(f"Copied info: {deep_copied_dict['info']}")    # 输出: Copied info: {'city': 'Boston'}
# 嵌套的可变对象的修改也没有影响原字典!

何时使用深拷贝?

深拷贝在你需要完全独立的数据副本时非常有用,尤其是在以下场景:

  1. 需要修改副本而不影响原始数据:这是最常见的用途,你有一个包含大量配置数据的字典,你想基于这个配置进行一些实验性修改,但又不想破坏原始配置。
  2. 序列化和反序列化:当你将一个复杂对象(如字典)转换为字符串(如 JSON)时,深拷贝可以确保原始对象不被意外修改。
  3. 多线程/多进程环境:当多个线程或进程需要访问同一个数据结构,但每个都需要自己的独立副本以避免竞争条件时。
  4. 缓存机制:当你缓存一个复杂对象时,深拷贝可以确保缓存的对象在后续被修改时,不会影响到原始数据。

性能和内存考量

深拷贝虽然功能强大,但也有一些缺点:

  • 性能开销:深拷贝需要递归地遍历整个对象及其内部的所有可变对象,这个过程比浅拷贝要慢得多。
  • 内存消耗:深拷贝会创建一个全新的、与原对象一样大的对象树,会消耗更多的内存。

只在确实需要创建完全独立的副本时才使用深拷贝,如果只是需要一个简单的备份,并且你确定只会修改不可变对象,或者不介意修改会同步到原对象,那么浅拷贝(.copy())是更高效的选择。

Python字典如何实现深拷贝?-图3
(图片来源网络,侵删)

总结与对比

特性 浅拷贝 (dict.copy()) 深拷贝 (copy.deepcopy())
创建方式 new_dict = old_dict.copy()copy.copy(old_dict) import copy; new_dict = copy.deepcopy(old_dict)
顶层字典 创建一个新对象 创建一个新对象
不可变元素 创建对原元素的引用 创建对原元素的引用(因为不可变,效果等同于复制)
可变元素 共享引用,修改会影响原对象 创建副本,修改不会影响原对象
嵌套对象 共享引用,修改会影响原对象 递归创建副本,修改不会影响原对象
性能 ,开销小 ,开销大
内存 ,只复制顶层结构 ,复制整个对象树
适用场景 当你只需要一个字典的独立外壳,且内部可变对象不需要被隔离时。 当你需要一个字典的完全独立的副本,任何修改都不能影响原数据时。

希望这个详细的解释能帮助你完全理解 Python 字典的 deepcopy

分享:
扫描分享到社交APP
上一篇
下一篇