Python引用机制与深浅拷贝详解
本文深入解析Python中变量引用的底层逻辑,区分直接赋值、浅拷贝与深拷贝的行为差异。通过对比C++等语言,阐明Python“一切皆引用”的概念,并详细说明在修改可变与不可变对象时,不同拷贝方式对原数据的影响及内存表现。
本文系统梳理Python中可变与不可变对象的各种浅拷贝与深拷贝规则。
Python一切皆引用
在C++或Java等语言中,int a = 1表示创建变量a并赋值为1;int b = a表示创建变量b,并将a的值赋给b。此时a与b互不影响,即“变量是盒子”。但这种模型不利于理解Python中的变量定义。在Python中,我们将变量视为“指向实际存储区域的引用”(图源:《流畅的python》)。

因此在Python中,a = [1, 2, 3]先分配一块内存区域写入[1,2,3],再让变量a指向它;b = a使变量b也指向同一个对象。即使a本身被删除(例如执行del a),这也仅仅是撕下了一张标签,b仍然可以访问该列表。其他数据类型遵循相同逻辑。
情况一:直接引用

直接引用即执行b = a。正如前文所述,这不会发生数据拷贝,只是让b也指向a所代表的内存区域。此时b与a指向同一对象,b[0]即等同于a[0]。
如果对a进行重新赋值(例如让a指向其他对象),则与原有列表无关,b的内容不会变化;但如果修改a[0](或使用+=、append等方法),则直接修改了列表内容,b[0]也会随之变化。

然而,对于整数、元组或字符串等不可变对象,虽然也可以使用+=操作,但它们不支持原地修改,因此实际上会调用a = a + b生成一个新对象。如a = (1, 2, 3); b = a; a += (4, 5)所示,此时执行a = a + (4, 5),a已指向新的值,所以b的内容保持不变。
情况二:复制
有时我们仅编辑列表或字典的副本,因此需要执行复制操作。一般最常见的复制方法包括:
b = a[:]
b = list(_ for _ in a)
b = copy(a)
b = a.copy()
这些方法均称为浅复制。浅复制时发生了什么?

浅复制的逻辑是创建一个新对象,并将原对象的每个值复制一份放入新对象中,耗时为线性时间。可以看到复制后b与a内容完全一致,但a is b不再成立,a[0]和b[0]也不再关联。你可以任意修改列表b,都不会影响a中的四个元素(红蓝橙绿四个小圆)。
情况三:深复制
但浅复制仍无法解决所有问题。我们知道Python中一切皆引用,图中的小圆并非盒子而是标签!虽然a与b本身已分开,但如果其中包含的元素仍是列表,它们之间实际上仍存在联系。

如图,浅复制时执行了b[1]=a[1],但b[1]和a[1]是引用,因此通过它们访问的仍是同一个可变序列。修改a[1]不会导致b[1]变化,但修改a[1][0]却会导致b[1][0]同步变化。
因此我们引入深复制来解决此问题:
from copy import deepcopy
a = [1, [1, 2, 3], "hello"]
b = deepcopy(a)
深复制的逻辑是:将每个值复制放入新对象中;如果某项表示可变迭代对象(如列表、字典或未经特殊定制的自定义类),则将该对象也递归复制一份。这样即可得到一份完全独立的拷贝。

总结
到此这篇关于Python中引用和拷贝规律的文章就介绍到这了,更多相关Python引用和拷贝内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













