python基础之深浅copy

引子

首先在了解python中的深浅拷贝之前,我们先花一点时间来了解一下python内存中变量的存储情况。对于python而言,变量的存储采用了引用语义的方式,存储的只是一个变量值所在的内存地址,而不是这个变量的本身。

首先大家先思考一个问题:b = ?

Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 3
>>> b = a
>>> a = 5

正确答案是3。为什么呢?根据上面的解释可以的知变量在引用的过程中调用的并非变量的值,而是该变量所存储的内存地址。

>>> a = 3
>>> b = a
>>> id(a)
1460043952
>>> id(b)
1460043952
>>> a = 5
>>> id(a)
1460044016

由于变量b指向的变量a的内存地址也就是‘1460043952‘,而在给a重新赋值的情况下a的内存地址发生了变化而b原本指向的就是a重新赋值前的内存地址。因此即使在给a重新赋值的情况下b也不会发生变化。

赋值

作用:数据间的引用

>>> l1 = [1,2,3]
>>> l2 = l1
>>> l1[0] = 4
>>> l1,l2
([4, 2, 3], [4, 2, 3])

由于上面写的比较详细了这里就不进行验证操作了通过id()函数自行查看内存地址进行验证

浅拷贝

作用:拷贝一份独立的数据,不包括子元素

浅拷贝的使用

# 方式一
>>> import copy
>>> a = 1
>>> b = copy.copy(a)

# 方式二
>>> l1  = [1,2,3,4]
>>> l2 = l1.copy()
>>> l2

浅拷贝的重新赋值操作

>>> l1  = [1,2,[3,4]]
>>> l2 = l1.copy()
>>> l2
[1, 2, [3, 4]]
>>> l1[1]=5
>>> l1,l2
([1, 5, [3, 4]], [1, 2, [3, 4]])
>>> l1[2].append(6)
>>> l1,l2
([1, 5, [3, 4, 6]], [1, 2, [3, 4, 6]])

通过上面的例子可以看出浅拷贝拷贝的是一份独立的列表,如果列表中嵌套了列表的话,子列表是不独立的(引用)。

验证:

>>> id(l1)
1655770326088
>>> id(l2)
1655768753672
# 通过内存地址查看两个列表的内存地址是不同的
>>> id(l1[0])
1460043888
>>> id(l2[0])
1460043888
# 通过内存地址查看两个列表中的元素内存地址相同
>>> id(l1[2])
1655770326024
>>> id(l2[2])
1655770326024
>>> id(l1[2][0])
1460043952
>>> id(l2[2][0])
1460043952
# 通过内存地址查看两个列表中的子列表内存地址完全相同(子列表共享)

普通列表:由于列表与列表中的元素的内存地址都是独立的,而浅拷贝则是给新的列表重新开辟一块内存地址,而列表总的元素则使用原列表的内存地址。如果对某个列表中的元素重新赋值,则会开辟新的内存地址,因此两个列表之间互相影响。

嵌套列表:,由于子列表是两个列表共享的,因此子列表并不是有单独的内存地址,,所以修改子列表中的值,两个列表都会受影响。

深拷贝

作用拷贝一份完全独立的数据

深拷贝的使用:

>>> import copy
>>> l1 = [1,2,3,[4,5]]
>>> l2 = copy.deepcopy(l1)
>>> l1,l2
([1, 2, 3, [4, 5]], [1, 2, 3, [4, 5]])

深拷贝的重新赋值操作

>>> l1[0] = 0
>>> l1,l2
([0, 2, 3, [4, 5]], [1, 2, 3, [4, 5]])
>>> l1[3][0] = 6
>>> l1,l2
([0, 2, 3, [6, 5]], [1, 2, 3, [4, 5]])

验证:

>>> id(l1[0])
1460043856
>>> id(l2[0])
1460043888
>>> id(l1[3])
1655770201544
>>> id(l2[3])
1655770325832
>>> id(l2[3][0])
1460043984
>>> id(l1[3][0])
1460044048

通过查看内存地址发现无论是列表中的元素还是子元素的内存地址都是完全独立的。由此可得通过深拷贝拷贝出来的数据是完全独立的

补充:

以上说明仅限与可变类型。

不可变类型的深浅copy都不会开辟新的内存空间

>>> a = 'hello world'
>>> b = copy.copy(a)
>>> a,b
('hello world', 'hello world')
>>> id(a),id(b)
(1655768754224, 1655768754224)

原文发布于微信公众号 - 渗透云笔记(shentouyun)

原文发表时间:2019-05-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券