深浅拷贝
我们来了解一下浅拷贝。浅拷贝:不管多么复杂的数据结构,浅拷贝都只会copy一层。
简单的说就是浅拷贝拷贝的只是嵌套列表的首地址 所以修改内层列表 源数据也会跟着改变
深拷贝是拷贝两层列表的地址
其实深拷贝就是在内存中重新开辟一块空间,不管数据结构多么复杂,只要遇到可能发生改变的数据类型,就重新开辟一块内存空间把内容复制下来,直到最后一层,不再有复杂的数据类型,就保持其原引用。这样,不管数据结构多么的复杂,数据之间的修改都不会相互影响。这就是深拷贝
浅拷贝通常只复制对象本身,而深拷贝不仅会复制对象,还会递归的复制对象所关联的对象。深拷贝可能会遇到两个问题:一是一个对象如果直接或间接的引用了自身,会导致无休止的递归拷贝;二是深拷贝可能对原本设计为多个对象共享的数据也进行拷贝。Python通过copy
模块中的copy
和deepcopy
函数来实现浅拷贝和深拷贝操作,其中deepcopy
可以通过memo
字典来保存已经拷贝过的对象,从而避免刚才所说的自引用递归问题;此外,可以通过copyreg
模块的pickle
函数来定制指定类型对象的拷贝行为。
deepcopy
函数的本质其实就是对象的一次序列化和一次返回序列化,面试题中还考过用自定义函数实现对象的深拷贝操作,显然我们可以使用pickle
模块的dumps
和loads
来做到,代码如下所示。
import pickle my_deep_copy = lambda obj: pickle.loads(pickle.dumps(obj))
列表的切片操作[:]
相当于实现了列表对象的浅拷贝,而字典的copy
方法可以实现字典对象的浅拷贝。对象拷贝其实是更为快捷的创建对象的方式。在Python中,通过构造器创建对象属于两阶段构造,首先是分配内存空间,然后是初始化。在创建对象时,我们也可以基于“原型”对象来创建新对象,通过对原型对象的拷贝(复制内存)就完成了对象的创建和初始化,这种做法更加高效,这也就是设计模式中的原型模式。在Python中,我们可以通过元类的方式来实现原型模式,代码如下所示。
import copy class PrototypeMeta(type): """实现原型模式的元类""" def __init__(cls, *args, **kwargs): super().__init__(*args, **kwargs) # 为对象绑定clone方法来实现对象拷贝 cls.clone = lambda self, is_deep=True: \ copy.deepcopy(self) if is_deep else copy.copy(self) class Person(metaclass=PrototypeMeta): pass p1 = Person() p2 = p1.clone() # 深拷贝 p3 = p1.clone(is_deep=False) # 浅拷贝