Python深浅复制
- 一般对象的复制
- 复杂对象的复制
最近遇到了有关Python中的copy与deepcopy问题,之前再Java里面好像也遇到了深浅复制的问题,但是Python中的深浅复制还不是很熟,就简单了解了一下它们2个的差别,可以供大家参考,不对的地方欢迎大家批评指正。
一般对象的复制
针对Python中简单对象的复制,copy和deepcopy没有什么区别,就是和大家通常理解的复制是一样的,在内存中新开辟一个空间,将原来地址中的数据拷贝到新的地址空间中。说明一下:我们这里所说的简单对象可以理解为最常见的对象,不包含的子对象的对象,也就是包含普通元素(数字,字符串)的对象,下面的一段代码,可以先看一下效果是怎样的。
import copy
if __name__ == '__main__':
a = [1, 2, 3, 4]
b = copy.copy(a)
c = copy.deepcopy(a)
print(a == b)
print(a is b)
print(a == c)
print(a is c)
执行上面的代码,我们可以看到执行结果,深复制和浅复制的执行结果是一样的,并没有什么差别:
True # 说明 a 和 b 所指向的对象的内容相同
False # 说明 a 和 b 所指向的不是同一个对象(地址不同)
True # 说明 a 和 c 所指向的对象的内容相同
False # 说明 a 和 c 所指向的不是同一个对象(地址不同)
可以用一张图来解释一下,为什么简单对象的深浅复制是一样的。
我们知道,上面的图中,变量a指向一个List对象(或者说是一个List对象的引用),该对象在内存中占用一个地址空间,当简单对象执行copy和deepcopy中的对象时,我们可以看到无论时深复制还是浅复制,都是在内存中新开辟一个地址空间,将原来对象中的内容复制过去,同时让b成为新对象的引用。因此,我们看到a和b指向的对象是不一致的,但是内容是相同的。
复杂对象的复制
复杂对象可以理解为另外包含其他简单对象的对象,也就是包含子对象的对象,例如:List中嵌套List,或者Dict中嵌套List等,对于复杂对象我们先来看一个简单的程序示例。
import copy
if __name__ == '__main__':
a = {'name': 'test', 'age': 56, 'address': [1, 2, 3, 4, 5]}
b = copy.copy(a)
print(a is b)
print(a['address'] is b['address'])
c = copy.deepcopy(a)
print(a is c)
print(a['address'] is c['address'])
看一下上面代码的执行结果:
False # 说明 a 和 b 不是同一个对象的引用
True # 说明 a中的address 和 b 中的 address 是同一个对象。黑人问号脸??
False # 说明 a 和 c 不是同一个对象的引用
False # 说明 a中的address 和 c 中的 address 不是同一个对象
下面我通过一张图,来大概解释一下为什么会出现上面的结果。PS:具体对象的对象不一定是按照图中的方式,为了能够说明原理,本图中将子对象的存储空间单独抽出,方便理解。
我们看到对于复杂对象(包含子对象的对象)的复制,深浅复制在实现原理上就有所不同了。通过上图我们可以看到,复杂对象的深浅复制的区别在于复杂对象的子对象。可以看到:
- 对于复杂对象中的简单数据部分,无论是深复制还是浅复制,我们可以看到,Python都是采用的直接在内存中开辟新的地址空间,然后将值复制到新的地址空间。
- 对于复杂对象的子对象部分来说:深复制是在内存中开辟一个新的空间,并且将子对象复制到新的地址空间,但是对于浅复制而言,我们可以看到并没有对子对象来开辟空间,通过图看到,新复制的对象和原来的对象同时指向了同一个List对象(也就是同一个对象的引用),所以我们看到a[‘address’]和b[‘address’]同时指向同一个对象。
上面的内容简单解释了下Python的深浅复制,不对的大家可以批评指正。