Python中的赋值语句不赋值对象,它们在目标和对象之间创建绑定。对于可变的或包含可变项的容器,有时需要一个副本,所有可以改变一个副本而不改变另一个。
浅复制
创建一个新对象,但它包含的是对原始对象包含的项的引用。
a = []
b = list(a)
c=a.copy()
d = copy.copy(a)
深复制
创建一个新对象,并且递归的复制它包含的所有对象。
import copy
b = []
a = copy.deepcopy(b)
当原始对象包含可变对象a,浅复制仅仅复制对a的引用。这时,如果a的值更改,那么相应新对象中a的值也会更改。
>> a=[1,2,3]
>>> b = {'x':['a','b'], 'y':a} #字典b的value都是可变对象
>>> c = copy.copy(b) #浅复制
>>> d = copy.deepcopy(b) #深复制
>>> a.pop() #修改a
3
>>> b
{'x': ['a', 'b'], 'y': [1, 2]} #原始对象b改变
>>> c
{'x': ['a', 'b'], 'y': [1, 2]} #浅复制c同样发生改变
>>> d
{'x': ['a', 'b'], 'y': [1, 2, 3]} #深复制d不变
>>> b['x'].append('c')
>>> b
{'x': ['a', 'b', 'c'], 'y': [1, 2]}
>>> c
{'x': ['a', 'b', 'c'], 'y': [1, 2]}
>>> d
{'x': ['a', 'b'], 'y': [1, 2, 3]}
使用内置函数id()来查看对象的标识
标识相当于内存中对象中的地址
>>> id(a)
50285512
>>> id(b['y'])
50285512
>>> id(c['y'])
50285512
>>> id(d['y'])
49946056
可以发现原始对象b['y']和浅复制对象c['y']的标识相同,和a引用同一个值,而深复制对象d['y']引用的是一个新的值,所以将a添加到浅复制对象c['y']中会导致递归引用。
>>> a
[1, 2]
>>> c['y'].append(a)
>>> c
{'x': ['a', 'b', 'c'], 'y': [1, 2, [...]]} #c['y']出现递归引用
>>> a.pop() #删除a中对a的引用
[1, 2]
>>> d
{'x': ['a', 'b'], 'y': [1, 2, 3, [1, 2]]} #d['y']和a引用的不是一个值,所以不会发生诋毁引用
实现简单的深浅复制
def mycopy(x):
'''''浅复制函数,接受list,tuple,set,dict类型的参数'''
types = {list,tuple,set}
cls = type(x)
if cls in types:
n = [item for item in x]
return cls(n)
elif cls is dict:
return {key:value for key,value in x.items()}
raise TypeError
参考:
https://www.yuque.com/docs/share/abfa1a00-0cd9-4a4f-bc20-55ea65249c72