- 1.拷贝概念
- 1.2 相关知识点
- 2.浅拷贝概念
- 3.浅拷贝演示
- 4.深拷贝概念
- 5.深拷贝演示
如果各位捧场的读者老爷对python中‘’is‘’和‘’==‘’运算符的概念如我一样有些许了解的话,那应该知道当我们在将一个变量赋予另一个变量如“a = b ”时,如果b的值在小整型缓存区(-5~256)内,那么所谓的将b值赋值给a就只是引用同一个内存数据罢了。深拷贝浅拷贝有点类似于这个,“浅”字在这里的意思就是浅浅一层,仅能能拷贝对象的表层,而其子对象,就是直接拿来引用了,所谓深拷贝就是用递归的原理把其子对象也依次拷贝下来,这就是两者的区别。
百般口舌不如一证,下面举些小例子用以说明,如果基础较差的读者可以按情况点击下面链接查看笔记。
1.2 相关知识点python篇 “is"和”=="
python篇 变量应用
python篇 面向对象
3.浅拷贝演示由上述定义可知,所谓浅拷贝即是只拷贝对象第一层而不拷贝其子对象。
对于列表的拷贝我们可以使用列表内置的copy方法,当然也可以使用copy模块的copy方法,都会讲到。废话不说了,开搞。
>>> ls1 = [1,2,3,4,5] >>> ls2 = ls.copy() >>> ls1 [1, 2, 3, 4, 5] >>> ls2 [1, 2, 3, 4, 5]
列表中的copy方法是浅拷贝,我们定义了ls1变量并赋值了一个列表对象,接着又把对象拷贝给了ls2,可以用内置方法id()查看拷贝后类ls1、ls2的内存地址,当然结果大家也应该知道浅拷贝是能拷贝对象第一层的,而非只是引用,所以内存地址必然不同。
>>> id(ls1) 744702724096 >>> id(ls2) 744702724160
故而在改变其中一个的值时另一个的值也不会改变
>>> ls1.append(6) >>> ls1 [1, 2, 3, 4, 5, 6] >>> ls2 [1, 2, 3, 4, 5]
但若是为需要拷贝的内容加上子对象呢?已经讲过子对象无法被浅拷贝所拷贝,这里我们就为ls1重新赋值加上一个列表子对象,再将其拷贝。
>>> ls1 = [1,2,3,[4,5,6]] >>> ls2 = ls1.copy() >>>> ls1 [1, 2, 3, [4, 5, 6]] >>> ls2 [1, 2, 3, [4, 5, 6]] >>> id(ls1) 744702725824 >>> id(ls2) 744702726080
如上面代码所示,第一层对象的拷贝是成功了的,但子对象…
>>> id(ls1[3]) 744702460544 >>> id(ls2[3]) 744702460544 >>>
就只是简单引用了,既然是引用的是同一个内存数据,那么我改变其中一个,另一个自然也要改变。
>>> ls1 [1, 2, 3, [4, 5, 6]] >>> ls2 [1, 2, 3, [4, 5, 6]] >>> ls1[3].append(9) >>> ls1 [1, 2, 3, [4, 5, 6, 9]] >>> ls2 [1, 2, 3, [4, 5, 6, 9]] >>>
为了方便拷贝,python中提供了对象拷贝模块,copy模块
用import copy命令引入该模块
import copy
在copy模块下亦有一个copy方法(copy.copy)与列表自带的copy方法功能相同,也是浅拷贝,就不多加赘述了,只是提一下,因为深拷贝要用到
>>> ls = [1,2,3,[1,2,3],4] >>> ls2 = ls.copy() >>> id(ls2[3]) //第二层 375434153856 >>> id(ls[3]) //第二层 375434153856 >>> ls[3][2]=22222 //操作子对象 >>> ls [1, 2, 3, [1, 2, 22222], 4] >>> ls2 [1, 2, 3, [1, 2, 22222], 4] >>> ls1 = copy.copy(ls) >>> ls1 [1, 2, 3, [1, 2, 22222], 4] >>> ls [1, 2, 3, [1, 2, 22222], 4] >>> id(ls) 375433973184 >>> id(ls[3]) 375434153856 >>> id(ls1[3]) 3754341538564.深拷贝概念
5.深拷贝演示由上述定义可知,所谓深拷贝即是拷贝对象并拷贝对象下的子对象。
我们已经了解了深拷贝的概念,现在具体使用,为了方便使用,我们这里也使用copy模块进行拷贝,而深拷贝的底层逻辑,是使用的递归原理完成拷贝,如果对递归概念不太了解可以点击下面的链接。
python篇 递归使用
下面介绍copy模块中另一个“copy”方法,也就是深拷贝方法:
copy.deepcopy,下面我们定义一个含有子对象的ls变量,并用深拷贝给ls1变量
>>> ls [1, 2, 3, [1, 2, 22222], 4] >>> ls1 = copy.deepcopy(ls) >>> ls1 [1, 2, 3, [1, 2, 22222], 4]
同样用全局函数id查看其子对象内存地址,可知其子对象内存地址值不同,已完成拷贝,而非简单引用。
>>> id(ls[3]) 744702914816 >>> id(ls1[3]) 744702725824
理所应该的改变其中一个的子对象,另一个不会发生改变。
>>> ls
[1, 2, 3, [1, 2, 22222], 4]
>>> ls[3].append("哈哈哈")
>>> ls
[1, 2, 3, [1, 2, 22222, '哈哈哈'], 4]
>>> ls1
[1, 2, 3, [1, 2, 22222], 4]
下面做个小总:
一般需要拷贝对象的时候,一般建议大家使用拷贝为浅拷贝,只拷贝一层,效率会高一点,占用内存会少一点,如果需要完全分离就使用深拷贝;
特殊情况:不可变类型(元组,字符串),无论浅拷贝还是深拷贝都永远只有一份(引用)
出道题感兴趣的可以下去尝试:
元组中的元素是可变的,浅拷贝和深拷贝会发生啥?
>>> t = (1,2,[3,4,5]) >>> tt = copy.copy(t) >>> ttt = copy.deepcopy(t) >>> ttt = copy.deepcopy(t) >>> t is tt True >>> t is ttt False >>>
答曰:会全数复制一份其不可变对象



