简介
在Python中,对于对象的拷贝,分为浅拷贝(copy)与深拷贝(deepcopy)两种方式。浅拷贝由操作符“=”完成,或者由copy模块中的copy方法完成,而深拷贝由copy模块中的deepcopy方法承担。
对于浅拷贝与深拷贝,如果拷贝对象都是不可变对象,则两者没有区别。
如果拷贝对象是可变对象,则浅拷贝只是拷贝了内存中对象的地址引用,而没有拷贝实际对象的数据内容,所以对浅拷贝与拷贝源任意一个进行修改,则另一个也跟着被修改。
而深拷贝对可变对象进行拷贝时,则拷贝的不仅仅是可变对象的地址引用,而且还拷贝可变对象在内存中的数据,修改任意一个对象,另一个拷贝对象不受影响。
代码演示:
>>> import copy
>>> origin = [1, 2, [3, 4]]
#origin 里边有三个元素:1, 2,[3, 4]
>>> cop1 = copy.copy(origin)
>>> cop2 = copy.deepcopy(origin)
>>> cop1 == cop2
True
>>> cop1 is cop2
False
#cop1 和 cop2 看上去相同,但已不再是同一个object
>>> origin[2][0] = "hey!"
>>> origin
[1, 2, ['hey!', 4]]
>>> cop1
[1, 2, ['hey!', 4]]
>>> cop2
[1, 2, [3, 4]]
#把origin内的子list [3, 4] 改掉了一个元素,观察 cop1 和 cop2
定制copy行为
在自定义类时,可通过魔法方法__copy()__与__deepcopy()__来实现浅拷贝与深拷贝。
魔法方法__copy()__没有任何参数,返回对象的浅拷贝。
魔法方法__deepcopy()__具有参数memo dictionary,返回对象的深拷贝。对象需要深拷贝的属性值都通过memo dictionary传递给方法,以控制拷贝的递归循环,为了避免递归循环地拷贝数据结构,deepcopy使用备忘录字典(memo dictionary)跟踪已经被拷贝的数据结构。
import copy
import functools
@functools.total_ordering
class MyClass:
def __init__(self, name):
self.name = name
def __copy__(self):
return MyClass(self.name)
def __deepcopy__(self, memo):
return MyClass(copy.deepcopy(self.name, memo))
a = MyClass("name")
sc = copy.copy(a)
dc = copy.deepcopy(a)