Python 深拷贝和浅拷贝详解
一、深拷贝和浅拷贝概念理解
1、浅拷贝,指的是重新分配一块内存,创建一个新的对象,但里面的元素是原对象中各个子对象的引用。
2、深拷贝,是指重新分配一块内存,创建一个新的对象,并且将原对象中的元素,以递归的方式,通过创建新的子对象拷贝到新对象中。因此,新对象和原对象没有任何关联。
3、对于不可变对象,深拷贝和浅拷贝的效果是一样的,因为不可变对象不需要在内存中复制
4、对于可变对象,深拷贝和浅拷贝的效果是有区别的,主要原因在于可变对象自身的可变性质
二、浅拷贝
浅拷贝,为新变量重新分配一块内存,和原来变量的内存不一样,但浅拷贝完,两个变量中的元素的值是一样的。
切片操作符 ‘:’ 不能用于字典和集合完成浅拷贝
浅拷贝是创建一个新对象,该对象的内容是原始对象的引用。换句话说,新对象与原始对象共享内存中的某些部分。当对其中一个对象进行更改时,另一个对象也会受到影响。浅拷贝可以通过切片操作符([:])或使用
copy
模块中的copy()
函数来实现。
1、使用数据类型本身的构造器(list() dict() set() 等)
list1 = [1, 2, 3] list2 = list(list1) print(list2) print("list1==list2 ?",list1==list2) # list1==list2 ? True print("list1 is list2 ?",list1 is list2) # list1 is list2 ? False set1= set([1, 2, 3]) set2 = set(set1) print(set2) print("set1==set2 ?",set1==set2) print("set1 is set2 ?",set1 is set2) dict1 = {1:[1,'w'], 2:0, 3:98} dict2 = dict(dict1) print(dict2) print("dict1 == dict2 ?",dict1 == dict2) print("dict1 is dict2 ?",dict1 is dict2)
2、对于可变的序列,还可以通过切片操作符 : 来完成浅拷贝
list1 = [1, 2, 3] list2 = list1[:] print(list2) print("list1 == list2 ?",list1 == list2) print("list1 is list2 ?",list1 is list2) [1, 2, 3] list1 == list2 ? True list1 is list2 ? False
3、Python 还提供了对应的函数 copy.copy() 函数,适用于任何数据类型
import copy list1 = [1, 2, 3] list2 = copy.copy(list1) print(list2) print("list1 == list2 ?",list1 == list2) print("list1 is list2 ?",list1 is list2) set1 = {1, 2, 3} set2 = copy.copy(set1) print(set2) print("set1 == set2 ?",set1 == set2) print("set1 is set2 ?",set1 is set2) dict1 = {1:'xiaoming', 2:'xiahua',3:'xiaoli'} dict2 = dict(dict1) print(dict2) print("dict1 == dict2 ?",dict1 == dict2) print("dict1 is dict2 ?",dict1 is dict2)
4、对于元组,使用 tuple() 或者切片操作符 ‘:’ 不会创建一份浅拷贝,相反它会返回一个指向相同元组的引用
tuple1 = (1, 2, 3) tuple2 = tuple(tuple1) print(tuple2) # (1, 2, 3) print("tuple1 == tuple2 ?",tuple1 == tuple2) # tuple1 == tuple2 ? True print("tuple1 is tuple2 ?",tuple1 is tuple2) # tuple1 is tuple2 ? True tuple1 = (1, 2, 3) tuple2 = tuple1[:] print(tuple2) # (1, 2, 3) print("tuple1 == tuple2 ?",tuple1 == tuple2) # tuple1 == tuple2 ? True print("tuple1 is tuple2 ?",tuple1 is tuple2) # tuple1 is tuple2 ? True
对字符串使用 str() 或者切片操作符 ‘:’,原理和 元组相同。
也就是说,对字符串和元组使用 copy()、[:]、本身的构造器完成的复制,都只是开辟了内存存储原对象的引用,而不是存储原对象的子对象的引用。
三、深拷贝
Python 中以 copy.deepcopy() 来实现对象的深度拷贝
深拷贝会创建一个新对象,并且递归地复制原始对象及其内容,而不仅仅是引用。深拷贝不共享任何内存地址,因此对其中一个对象的更改不会影响另一个对象。
import copy list1 = [[1, 2], (30, 40)] list2 = copy.deepcopy(list1) # 深拷贝 list3 = copy.copy(list1) # 浅拷贝 list1[0].append(100) # 子元素添加值 print("list1:", list1) # list1 变 print("list2:", list2) # 深拷贝以后和list1没有关系,list2不变 print("list3:", list3) # 浅拷贝是存储原对象的子对象的引用,所以跟着改变