Python的复制与拷贝-----奶奶看了直呼好家伙!

变量与赋值

在 Python 中,一切皆为对象,对象通过「变量名」引用,「变量名」更确切的叫法是「名字」,好比我们每个人都有自己的名字一样,咱们通过名字来代指某个人,代码里面通过名字来指代某个对象。

变量赋值就是给对象绑定一个名字,赋值并不会拷贝对象。好比我们出生的时候父母就要给我们取一个名字一样,给人取个绰号并不来多出一个人来,只是多一个名字罢了。

两个对象做比较有两种方式,分别是:is 与 == , is 比较的是两个对象是否相同,通过对象的ID值可识别是否为相同对象,== 比较的是两个对象的值是否相等

>>> x1 = [1,2]
>>> x2 = [1,2]
>>> x1 is x2
False

>>> id(x1)
4338854088
>>> id(x2)
4338904392

>>> x1 == x2
True
Python的复制与拷贝-----奶奶看了直呼好家伙!

x1 和 x2 的值虽然相同,但在内存中是两个独立的不同的对象,占据不同的内存空间,就好比两个长得一样的苹果摆在桌子上,实则为两个不同的物体。

>>> x3 = x2
>>> x3 is x2
True
>>> id(x3)
4338904392
Python的复制与拷贝-----奶奶看了直呼好家伙!

很多人学习python,不知道从何学起。
很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
很多已经做案例的人,却不知道如何去学习更加高深的知识。
那么针对这三类人,我给大家提供一个好的学习平台,免费领取视频教程,电子书籍,以及课程的源代码!
QQ群:609616831


前面说了,赋值是给对象绑定名字,这里我们只不过是给 x2 对应的那个对象绑定了一个新的名字叫 x3,这就好比桌上放了一个苹果,开始给它贴了一个 x2 的标签,后来又给它添了一个 x3 的标签,本质上还是同一个苹果,所以,x2 和 x3 所指的其实是同一个对象。

Python的复制与拷贝-----奶奶看了直呼好家伙!Python的复制与拷贝-----奶奶看了直呼好家伙!

Python的复制与拷贝-----奶奶看了直呼好家伙!Python的复制与拷贝-----奶奶看了直呼好家伙!

通过x2 修改对象时,x3 也会跟着变化,因为本质上它们是同一个对象,这就好比张三和小张是同一个人时,给张三添衣服其实就是给小张添衣服。

>>> x2.append(3)
>>> x2
[1, 2, 3]
>>> x3
[1, 2, 3]
Python的复制与拷贝-----奶奶看了直呼好家伙!

但是,当我给 x2 重新赋值时,相当于 x2 不再引用之前的对象,而引用新对象, x3 依然引用之前的对象。好比桌上一大苹果开始贴了 x2 和 x3 两个标签,给 x2 重新赋值就相当于把 x2 标签贴到另外一个苹果,但是 x3 还是贴在老苹果身上。

>>> x2 = [3, 4]
>>> x3
[1, 2, 3]
Python的复制与拷贝-----奶奶看了直呼好家伙!

Python的复制与拷贝-----奶奶看了直呼好家伙!Python的复制与拷贝-----奶奶看了直呼好家伙!

对象拷贝

在业务中有时我们需要复制一个对象,但是又不想对原对象产生副作用,肯定不能通过赋值给一个新变量来解决(因为赋值不是拷贝对象),所以 Python 专门提供了一种拷贝机制,基于原对象快速创建出一个含有相同值的对象。该功能由 copy 模块提供。

 

拷贝又分为浅拷贝和深拷贝。

>>> s = [1,2,3]
>>> sc = copy.copy(s) # 浅拷贝
>>> sc
[1, 2, 3]
Python的复制与拷贝-----奶奶看了直呼好家伙!
>>> sdc = copy.deepcopy(s)  # 深拷贝
>>> sdc
[1, 2, 3]
Python的复制与拷贝-----奶奶看了直呼好家伙!

拷贝出来的对象只是值相同,实为不同的对象

>>> s == sc == sdc 
True
>>> s is sc 
False
>>> s is sdc
False
Python的复制与拷贝-----奶奶看了直呼好家伙!

那么浅拷贝(shallow copy)与深拷贝(deep copy)有什么区别呢?

对于不可变对象,比如整数、字符串、元组、还有由这些不可变对象组成的集合对象,浅拷贝和深拷贝没有区别,都是拷贝一个新对象

两者的区别在于拷贝组合对象,比如列表中还有列表,字典中还有字典或者列表的情况时,浅拷贝只拷贝了外面的壳子,里面的元素并没有拷贝,而深拷贝则是把壳子和里面的元素都拷贝了一份新的。

来看一个例子:

>>> x = [2, 3]
>>> y = [7, 11]
>>> z = [x, y]

>>> a = copy.copy(z) # 浅拷贝
>>> a[0] is z[0]
True
Python的复制与拷贝-----奶奶看了直呼好家伙!

Python的复制与拷贝-----奶奶看了直呼好家伙!Python的复制与拷贝-----奶奶看了直呼好家伙!

拷贝出来的对象 a 中的元素引用的是 x 和 y,当你修改 x 的值,a 也会跟着变。

>>> b = copy.deepcopy(z) # 深拷贝
>>> b[0] is z[0]
False
Python的复制与拷贝-----奶奶看了直呼好家伙!

Python的复制与拷贝-----奶奶看了直呼好家伙!Python的复制与拷贝-----奶奶看了直呼好家伙!

对于深拷贝,里面的元素也重新拷贝了一份,拷贝了一份与x和y等值的两个元素,修改 x 和 y 的值,不会对 b 产生影响

 

对列表的切片拷贝 z[:] 或者是调用对象的copy方法 list.copy() 都属于浅拷贝。对于自定义对象,我们还可以自己实现 __copy__方法和 __deepcopy__方法

在这里还是要推荐下我自己建的Python学习群:609616831,群里都是学Python的,如果你想学或者正在学习Python ,欢迎你加入,大家都是软件开发党,不定期分享干货(只有Python软件开发相关的),包括我自己整理的一份2020最新的Python进阶资料和零基础教学,欢迎进阶中和对Python感兴趣的小伙伴加入!

上一篇:公平博弈必输策略及Python改进


下一篇:Python基础学习笔记——输入三角形三个顶点的坐标,计算三角形的面积