Python中的浅复制与深复制
1. 元组:元组是不可变的有序列表。
1 a= [30,40] 2 tuple_a = (1, 2, a) 3 a[0] = 3 4 tuple_a 5 # >>> (1, 2, [3, 40]) # 元组是不可变的,但是元组中的元素如果是引用(某个对象的地址),引用的对象是可能会改变的。
2. copy模块中的copy方法可能可以浅复制一个对象。
浅复制的意思是: (1)创建一个新的对象,(2)将原始对象中找到的子对象插入其中。(如果子对象是引用,则复制引用而不是复制引用的对象)
import copy a= [30,40] list_a = [1,2,a] list_b = copy.copy(list_a) list_a is list_b # 返回False。list_a和list_b是两个不同的对象,copy.copy(list_a)执行了浅复制 tuple_a = (1, 2, a) tuple_b =copy.copy(tuple_a) tuple_a is tuple_b # 返回True。根本没有进行浅复制,copy.copy(tuple_a) 直接返回了tuple_a
为什么copy.copy对于不同的对象有不同的行为? copy.copy会使用对象中定义的__copy__或者copy方法,如果对象没有定义相关方法,就直接返回这个对象。
a= [30,40] tuple_a = (1, 2, a) list_a = [1,2,a] # 通过obj.cpoy()调用对象的__copy__,或copy方法 tuple_a.copy() # 报错,因为元组没有copy方法。 list_a.copy() # 正常执行,因为list有cpoy方法 dir(tuple_a) # 查看对象的方法,可以进一步验证这一点
3. 对一个序列进行切片操作,默认执行的是浅复制。根据上一条,浅复制行为又取决于对象中是否定义了、如何定义浅复制。
a= [30,40] list_a = [1,2,a] slice_list_a = list_a[:] # 等同于: slice_list_a = copy.copy(list_a)。 也等同于: slice_list_a = list(list_a) list_a is slice_list_a # False tuple_a = (1, 2, a) slice_tuple_a = tuple_a[:] # 等同于: slice_tuple_a = copy.copy(tuple_a)。也等同于: slice_tuple_a = tuple(tuple_a) tuple_a is slice_tuple_a # True
4. 深复制
深复制的意思是:(1)创建一个新的对象,(2)递归地将在原始对象里找到的子对象的副本插入其中。
简单说就是:副本和父本的内容一样,但是不会相互影响。
5. 结论
- 浅复制和深复制的结果只在复合对象(对象包含引用)才有差别。
- 明确要求副本和父本不相互影响,最好进行深复制。
- 深复制(copy.deepcopy)和浅复制(copy.copy)都会受对象中定义的相关方法所影响,或者说会根据对象的不同,采取不同的行为。
a = 1
b = copy.deepcopy(a)
a is b # True。因为python中,多个相同的字面量的对象,都是一个对象。或者说,python只会为一个字面量建立最多一个对象。