深入理解 Python 中的深拷贝与浅拷贝
在 Python 编程中,对象的拷贝是一个常见的操作。Python 提供了两种拷贝方式:深拷贝(deep copy)和浅拷贝(shallow copy)。
这两种拷贝方式在处理对象时有着不同的行为和用途。本文将深入探讨它们之间的区别以及如何在实际编程中做出选择。
先谈谈拷贝的基本概念
在 Python 中,拷贝可以创建一个对象的副本,这个副本可以独立于原始对象进行修改。拷贝分为深拷贝和浅拷贝,它们的区别在于拷贝过程中对象内部引用的处理方式。
|浅拷贝(Shallow Copy)|
浅拷贝创建一个新对象,它是原始对象的一个副本,但是这个副本中包含的是对原始对象中元素的引用。换句话说,浅拷贝不会递归复制对象的内部结构。
实现方式:可以通过 copy 模块中的 copy()函数实现。
适用场景:当对象内部没有可变对象或者不需要复制对象内部的可变对象时。
|深拷贝(Deep Copy)|
深拷贝会创建一个新对象,并且递归复制所有对象的子对象,为所有对象创建新的实例。这意味着深拷贝会复制对象及其子对象的整个层次结构。
实现方式:可以通过 copy 模块中的 deepcopy()函数实现。
适用场景:当对象内部包含可变对象,并且需要完全独立于原始对象的副本时。
让我举个栗子
预期输出结果
浅拷贝:
使用 copy.copy() 创建了 original_dict 的浅拷贝。
浅拷贝只复制了字典的外层,内部的列表 [1, 2, 3] 和 [4, 5] 并没有被复制,只是被引用。
当我们修改了浅拷贝中的列表元素(将 [1, 2, 3] 的第一个元素改为 99)时,原始字典中的相应列表也发生了变化。
深拷贝:
使用 copy.deepcopy() 创建了 original_dict 的深拷贝。
深拷贝递归地复制了字典以及其内部的所有对象,创建了完全独立的副本。
当我们向深拷贝中的列表添加新元素时([4, 5] 变为 [4, 5, 6]),原始字典及其浅拷贝中的列表没有受到影响。
从分配内存的角度认识它们
浅拷贝
创建了一个新的字典对象,这个新对象拥有自己的内存空间。
可以理解为在内存中创建了一个新字典的“外壳”,但内部的“填充物”(即嵌套的对象)仍然指向原始对象的内存地址。因此,浅拷贝是一种“表面”的复制,内部对象的引用并未改变。
深拷贝
深拷贝不仅创建了一个新的字典对象,还递归地为字典内所有可变对象(如列表、字典等)创建了全新的实例。这意味着深拷贝为所有复制的对象分配了新的内存空间。
可以理解为是在内存中为原始对象及其所有嵌套对象创建了一个完全独立的副本。每个对象都获得了新的内存地址,与原始对象的内存地址不同。因此,深拷贝是一种“彻头彻尾”的复制,所有内容都是全新的实例。
从性能角度认识它们
在性能方面,深拷贝和浅拷贝有显著的区别,主要体现在以下几个方面:
深拷贝
内存使用:深拷贝会为原始对象中的每个对象创建一个全新的实例,这意味着它需要更多的内存空间来存储这些副本。
CPU 使用:深拷贝需要递归地遍历原始对象中的所有对象,并逐个复制,这个过程可能会非常耗时,特别是当对象包含大量子对象或层级较深时。
性能开销:由于需要复制整个对象层次结构,深拷贝的性能开销通常比浅拷贝大得多。
适用场景:深拷贝适用于需要完全独立的对象副本,且不介意额外的内存和时间开销的场景。
浅拷贝
内存使用:浅拷贝只创建一个新对象,而对象内部的引用(如列表、字典等)并不复制,因此内存使用较少。
CPU 使用:由于不涉及递归复制,浅拷贝的 CPU 使用通常较低,创建速度较快。
性能开销:浅拷贝的性能开销相对较小,因为它只涉及创建一个新对象的开销。
适用场景:浅拷贝适用于对象内部的可变对象不需要被独立修改,或者性能要求较高的场景。
总结
浅拷贝:节省内存,但修改拷贝对象可能影响原始对象。
深拷贝:内存消耗更大,但修改拷贝对象不会影响原始对象
原文链接:https://blog.csdn.net/weixin_60707895/article/details/138967625
评论