浅拷贝和深拷贝
1、对象赋值实际上是简单的对象引用。如下代码,a和b引用了同一块内存区域,这块内存区域存放着数字5。
>>> a = 5 >>> b = a >>> id(a) 19193872 >>> id(b) 19193872
2、浅拷贝
>>> listO = ['string', ['list', 'list']] >>> list1 = listO[:] #用切片操作默认为浅拷贝 >>> list2 = list(listO) #用工厂方法也是浅拷贝 >>> [id(x) for x in listO, list1, list2] #三个list对象存放在不同内存区域 [29443456, 29445176, 29153480] >>> [id(x) for x in listO] #但是浅拷贝后,容器的元素是原来对象元素的引用,三个list对象的元素都指向相同的内存区域 [19318432, 29443416] >>> [id(x) for x in list1] [19318432, 29443416] >>> [id(x) for x in list2] [19318432, 29443416] >>> list1[0] = 'string1' #字符串是不可变对象,所以创建了新的string对象,并使list1[0]指向它 >>> list1 ['string1', ['list', 'list']] >>> list2 #list2[0]还指向原来的对象 ['string', ['list', 'list']] >>> list1[1].append('add') #列表是可变的对象,在原对象上修改,没有创建新对象 >>> list1 ['string1', ['list', 'list', 'add']] >>> list2 #list1[1]和list2[1]指向同一对象,所以list2[1]也被修改了 ['string', ['list', 'list', 'add']]
3、深拷贝,或者说完全拷贝
>>> import copy >>> listO = ['string', ['list', 'list']] >>> list1 = listO[:] >>> list2 = copy.deepcopy(listO) >>> [id(x) for x in listO, list1, list2] [29442896, 29443456, 29451688] >>> [id(x) for x in listO] [19318432, 29452688] >>> [id(x) for x in list1] [19318432, 29452688] >>> [id(x) for x in list2] #注意这里和浅拷贝的不同,list2[1]和list1[1]指向不同的对象,而不可变类型元素list2[0]还是指向原来的对象 [19318432, 29483056]
4、关于拷贝操作
- 非容器类型没有拷贝一说
- 如果容器里只包含不可变类型对象,对它的深拷贝将不会进行。(因为深拷贝只是在可变对象上动手脚)
- 在copy模块中只有两个可用函数:copy()进行浅拷贝操作、deepcopy()进行深拷贝操作