python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python引用和拷贝

Python中的引用和拷贝规律详解

作者:Ofnoname

在python中无论是直接的变量赋值,还是参数传递,都是按照引用进行赋值的,这篇文章主要给大家介绍了关于Python中引用和拷贝规律的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下

python的可变不可变与各种浅拷贝深拷贝规则,一并梳理。

Python一切皆引用

在C++/Java里,int a = 1就是创建变量为a,赋值为1;int b = a就是创建变量b,赋值为a的值。a与b是毫不相干的,即“变量是盒子”,但是这不利于理解Python中的一个变量定义。在Python里,我们把变量视为“一个实际存储的引用”(图源:《流畅的python》)。

所以在python里,a = [1, 2, 3]先分配一块区域写入[1,2,3],再让a来代表它;b = a让b与a代表了同一个东西,即使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),已经指向新的值了,所以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引用和拷贝内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文