Python 中有6个标准的数据类型,它们又分为可变对象和不可变对象
不可变对象:Number(数字)、String(字符串)、Tuple(元组)
可变对象:List(列表)、Dictionary(字典)、Set(集合)
可变对象是指,一个对象在不改变其所指向的地址的前提下,可以修改其所指向的地址中的值
不可变对象是指,一个对象所指向的地址上值是不能修改的,如果你修改了这个对象的值,那么它指向的地址就改变了,相当于你把这个对象指向的值复制出来一份,然后做了修改后存到另一个地址上了,但是可变对象就不会做这样的动作,而是直接在对象所指的地址上把值给改变了,而这个对象依然指向这个地址
下面每个复制和拷贝,都是以list1为对象操作,list里面有2个元素,[1,2]为列表,为可变对象,'python'为字符串,为不可变对象
赋值
list1 = [[1,2],'python'] #复制:只是复制了list1指向内存地址的引用,list1和list2都指向同一个内存地址,其内元素仍旧指向相同内存地址 list2 = list1 print('复制') print(f'list2:{list2},\nlist2的内存地址:{str(id(list2))}\n(列表为可变数据类型)的内存地址:{str(id(list2[0]))}\n字符串的内存地址(字符串为不可变数据类型):{str(id(list2[1]))}') print(f'list1:{list1},\nlist1的内存地址:{str(id(list1))}\n(列表为可变数据类型)的内存地址:{str(id(list1[0]))}\n字符串的内存地址(字符串为不可变数据类型):{str(id(list1[1]))}') list2[1] ='林' list1[0][0] = 2print(f'list2:{list2},\nlist2的内存地址:{str(id(list2))}\n(列表为可变数据类型)的内存地址:{str(id(list2[0]))}\n字符串的内存地址(字符串为不可变数据类型):{str(id(list2[1]))}') print(f'list1:{list1},\nlist1的内存地址:{str(id(list1))}\n(列表为可变数据类型)的内存地址:{str(id(list1[0]))}\n字符串的内存地址(字符串为不可变数据类型):{str(id(list1[1]))}')
打印输出:
复制 list2:[[1, 2], 'python'], list2的内存地址:2148111806024 (列表为可变数据类型)的内存地址:2148111826824 字符串的内存地址(字符串为不可变数据类型):2148109419184 list1:[[1, 2], 'python'], list1的内存地址:2148111806024 (列表为可变数据类型)的内存地址:2148111826824 字符串的内存地址(字符串为不可变数据类型):2148109419184 list2:[[2, 2], '林'], list2的内存地址:2148111806024 (列表为可变数据类型)的内存地址:2148111806216 字符串的内存地址(字符串为不可变数据类型):2148109340064 list1:[[2, 2], '林'], list1的内存地址:2148111806024 (列表为可变数据类型)的内存地址:2148111806216 字符串的内存地址(字符串为不可变数据类型):2148109340064
当list1 = list2 进行复制,未改变元素值的时候:
list1和list2指向的内存地址一致,且两者内的可变对象和不可变对象的所指向内存地址也是一致的
当改变list2中元素值和list1中元素值的时候:
list2[1] ='林' list1[0][0] = 2
list1和list2指向的内存地址仍旧一致,表现为:改变list2的元素值的时候,list1内的元素值也跟着一起改变
list1、list2里面的可变对象和不可变对象的指向的内存地址与之前 未改变元素值的指向的内存地址有所变动。但改变元素值后,list1和list2里面可变对象和不可变对象所指向的内存一致(所以复制,不管对list1还是list2中的可变对象或不可对象的值进行修改,都会影响到另外一个list中所对应的元素值)
浅拷贝
list3 = copy.copy(list1) print('浅拷贝') print(f'list3:{list3},\nlist3的内存地址:{str(id(list3))}\n(列表为可变数据类型)的内存地址:{str(id(list3[0]))}\n字符串的内存地址(字符串为不可变数据类型):{str(id(list3[1]))}') print(f'list1:{list1},\nlist1的内存地址:{str(id(list1))}\n(列表为可变数据类型)的内存地址:{str(id(list1[0]))}\n字符串的内存地址(字符串为不可变数据类型):{str(id(list1[1]))}') list3[1] ='林' list3[0][0] = 2 print(f'list3:{list3},\nlist3的内存地址:{str(id(list3))}\n(列表为可变数据类型)的内存地址:{str(id(list3[0]))}\n字符串的内存地址(字符串为不可变数据类型):{str(id(list3[1]))}') print(f'list1:{list1},\nlist1的内存地址:{str(id(list1))}\n(列表为可变数据类型)的内存地址:{str(id(list1[0]))}\n字符串的内存地址(字符串为不可变数据类型):{str(id(list1[1]))}') print('='*50)
打印输出:
浅拷贝 list3:[[1, 2], 'python'], list3的内存地址:2934480629576 (列表为可变数据类型)的内存地址:2934480650184 字符串的内存地址(字符串为不可变数据类型):2934478242480 list1:[[1, 2], 'python'], list1的内存地址:2934480629384 (列表为可变数据类型)的内存地址:2934480650184 字符串的内存地址(字符串为不可变数据类型):2934478242480 list3:[[2, 2], '林'], list3的内存地址:2934480629576 (列表为可变数据类型)的内存地址:2934480650184 字符串的内存地址(字符串为不可变数据类型):2934478163440 list1:[[2, 2], 'python'], list1的内存地址:2934480629384 (列表为可变数据类型)的内存地址:2934480650184 字符串的内存地址(字符串为不可变数据类型):2934478242480
使用copy.copy(list1)对list1进行浅拷贝,生成list3,不对元素值进行改动:
list1与list3所指向的内存地址不一致,但list1、list3中的可变对象与不可变对象的所指向的内存地址仍是一致的
对浅拷贝的list3的元素值进行改动:
list3[1] ='林' list3[0][0] = 2
list3可变对象列表中的元素值发生改动,但所指向的内存地址无变化,所以list3可变对象的值的改动,会同步到list1上
list3不可变对象字符串的元素值发生改动,但所指向的内存地址发生变化,所以list3不可变对象的值的改动,不会同步到list1上
同样的道理,对原始数据list1的元素进行改动:
list1[1] ='林'
list1[0][0] = 2
打印输出:
浅拷贝 list3:[[1, 2], 'python'], list3的内存地址:3089021726536 (列表为可变数据类型)的内存地址:3089021747144 字符串的内存地址(字符串为不可变数据类型):3089020388016 list1:[[1, 2], 'python'], list1的内存地址:3089021726344 (列表为可变数据类型)的内存地址:3089021747144 字符串的内存地址(字符串为不可变数据类型):3089020388016 list3:[[2, 2], 'python'], list3的内存地址:3089021726536 (列表为可变数据类型)的内存地址:3089021747144 字符串的内存地址(字符串为不可变数据类型):3089020388016 list1:[[2, 2], '林'], list1的内存地址:3089021726344 (列表为可变数据类型)的内存地址:3089021747144 字符串的内存地址(字符串为不可变数据类型):3089020308976
可以看到,结果与上面对list3中元素值进行修改一致
所以浅拷贝
改变原始数据list1或浅拷贝数据lsit3中可变对象的元素值,都会保持同步,所指向的内存地址一致(在可变类型的数据中,如果存在嵌套的结构类型,浅拷贝只复制最外层的数据,导致内存地址发生变化,里面数据的内存地址不会变)
改变原始数据list1或浅拷贝数据lsit3中不可变对象的元素值,改变后所指向的内存地址发生改变,所以不会对另一部分元素值造成影响
深拷贝
深拷贝拷贝了对象的所有元素,包括多层嵌套的元素。深拷贝出来的对象是一个全新的对象,不再与原来的对象有任何关联
#深拷贝 list4 = copy.deepcopy(list1) print('深拷贝') print(f'list4:{list4},\nlist4的内存地址:{str(id(list4))}\n(列表为可变数据类型)的内存地址:{str(id(list4[0]))}\n字符串的内存地址(字符串为不可变数据类型):{str(id(list4[1]))}') print(f'list1:{list1},\nlist1的内存地址:{str(id(list1))}\n(列表为可变数据类型)的内存地址:{str(id(list1[0]))}\n字符串的内存地址(字符串为不可变数据类型):{str(id(list1[1]))}') list4[1] ='林' list4[0][0] = 2 print(f'list4:{list4},\nlist4的内存地址:{str(id(list4))}\n(列表为可变数据类型)的内存地址:{str(id(list4[0]))}\n字符串的内存地址(字符串为不可变数据类型):{str(id(list4[1]))}') print(f'list1:{list1},\nlist1的内存地址:{str(id(list1))}\n(列表为可变数据类型)的内存地址:{str(id(list1[0]))}\n字符串的内存地址(字符串为不可变数据类型):{str(id(list1[1]))}')
打印输出:
深拷贝 list4:[[1, 2], 'python'], list4的内存地址:2071927320264 (列表为可变数据类型)的内存地址:2071927314184 字符串的内存地址(字符串为不可变数据类型):2071924933296 list1:[[1, 2], 'python'], list1的内存地址:2071927320456 (列表为可变数据类型)的内存地址:2071927320392 字符串的内存地址(字符串为不可变数据类型):2071924933296 list4:[[2, 2], '林'], list4的内存地址:2071927320264 (列表为可变数据类型)的内存地址:2071927314184 字符串的内存地址(字符串为不可变数据类型):2071924854256 list1:[[1, 2], 'python'], list1的内存地址:2071927320456 (列表为可变数据类型)的内存地址:2071927320392 字符串的内存地址(字符串为不可变数据类型):2071924933296
使用copy.deepcopy(list1)对list1进行深拷贝,生成list4,不对元素值进行改动:
list1与list4所指向的内存地址不一致,但list1、list4中的可变对象列表指向的内存地址发生改动,不可变对象字符串指向的内存地址没有发生改变
我们可以得出结论:
1、 深拷贝对最外层数据是只拷贝数据,会开辟新的内存地址来存放数据
2、深拷贝对里面的不可变数据类型直接复制数据和地址,和可变类型的浅拷贝是相同的效果
对深拷贝的list4中的元素值进行修改:
list4[1] ='林' list4[0][0] = 2
不管是可变对象,还是不可变对象,都不会对原始数据list1造成影响,反之亦然
标签:python,list1,数据类型,str,字符串,拷贝,内存地址,id,赋值 From: https://www.cnblogs.com/trystudy/p/16710064.html