Python中浅拷贝(copy)与深拷贝(deepcopy)的区别和用法详解

一:对象与元素、可变与不可变:
        (1)对象:对象有存储地址id【就好像某个地址的快递仓库】,对象中的元素都有一个地址id【就像仓库的某某货架】
        (2)对象与对象的元素:(对象)或(对象中的元素)有不同的类型【数字,字符串,列表,字典,集合,元组】
        (3)可变类型与不可变类型:
           定义:可变就是增删改查之后,对象或元素的存储id不会发生改变,反之就不可变
                 1.可变类型:其中【列表,字典,集合】是可变类型
                 2.不可变类型:【数字,字符串,元组】是不可变数据类型
list1 = [[1, 2], (30, 40),'kkk']
        (4)举例:例如以上的列表list1中,有[1, 2]、(30, 40)、'kkk'三个元素,首先列表本身list1是可变的类型,元素[1, 2]是可变的,元素(30, 40)和'kkk'是不可变的

二、深拷贝与浅拷贝的异同:

        1.相同点:       

无论深拷贝还是浅拷贝都会创建一个新对象。即:拷贝出来的对象的id不同。

        2.不同点:

浅拷贝:只拷贝了对象,对象内的元素并不会发生拷贝。
深拷贝:不仅拷贝对象,对象内的元素也会发生拷贝。

三、浅拷贝:

#encoding=utf-8
import copy

# (1)对象有一点地址id【就好像某个地址的快递仓库】,对象中的元素都有一个地址id【就像仓库的某某货架】
# (2)(对象)或(对象中的元素)有不同的类型【数字,字符串,列表,字典,集合,元组】,其中【列表,字典,集合】是可变类型,其他的是不可变数据类型
#    可变就是增删改查之后,对象的存储id都不会发生改变,反之就不可变
#(3)例如以下的列表list1中,有[1, 2]、(30, 40)、'kkk'三个元素,首先列表本身list1是可变的类型,元素[1, 2]是可变的,元素(30, 40)和'kkk'是不可变的
list1 = [[1, 2], (30, 40),'kkk']
# print(id(list1[2]),list1[2])
# print(id(list1),list1)
# list1[2]='mmm'
# print(id(list1),list1)
# print(id(list1[2]),list1[2])
#一、浅拷贝:拷贝的对象新建一个id,但是与原对象的内部元素是相同的
copy1=copy.copy(list1)
print(id(list1),id(copy1))  #新的对象与原对象的id是不同的,所以是两个不同的对象
print(list1 is copy1)       #所以这里是false
print(list1[0] is copy1[0]) #虽然对象不同,但是对象内部的元素是同一个,True

'''
二、浅拷贝的修改:上面说到了浅拷贝得到的前后对象是不同的,但是内部元素是相同的,所以这些对象的内部元素是同一个东西,但是....
      但是这(并不)代表新生成的对象(一定)会随着原对象的改变而改变【并不一定】,就是有可能会变,也有可能不变
      是否同时改变的判断标准:原对象被修改的元素是否可变类型。两种情况:被修元素可变、被修元素不可变
        (1)如果原对象的被修改对象是【可变类型】,同时改变,且这些修改前后的元素的id也不会改变
        (2)如果原对象的被修改对象是【不可变类型】,新生成的对象不会随之改变,且原对象修的元素的id也改变,新对象的元素id不会发生改变
'''
#(1)修改可变元素----对象随之改变,元素前后id不变
print('====================')
list1 = [[1, 2], (30, 40),'kkk']
copy2=copy.copy(list1)
print(id(list1)==id(copy2))  #id不同,所以是false
print(list1==copy2)          #id不同,但是内容元素相同,true
print(list1[0] is copy2[0])  #元素相同,所以是true
print(id(copy2[0]))          #修改前的元素的id:1630833789704
#开始修改list1中的元素[1,2],增加一个5
list1[0].append(5)
print(id(list1)==id(copy2))  #false
print(list1==copy2)          #true修改后两个对象依旧==相等,但是是两个对象(is)--->说明新对象同步变化了
print(id(copy2[0]))          #修改后的元素的id:1630833789704
print(list1[0] is copy2[0])  #元素是同一个,true

#(2)修改不可变元素----对象不会随之改变,且原对象修的元素的id也改变,新对象的元素id不会发生改变
print('====================')

list2 = [[1, 2], (30, 40),'kkk']
copy3=copy.copy(list2)
print(id(list2)==id(copy3))  #id不同,所以是false
print(list2==copy3)          #id不同,但是内容元素相同,true
print(list2[1] is copy3[1])  #元素相同,所以是true
print(id(copy3[1]),'\n',id(list2[1]))          #修改前的元素的id是同一个:2165500139912
print('%%%%%%%%%%')
print(list2,'\n',copy3)      #相同是同一内容
#开始修改list2中的元素(30,40),增加一个(50,60)
list2[1]+=(50,60)
print(id(list2)==id(copy3))  #false
print(list2==copy3)          #false修改后两个对象内容不再相等
print(id(copy3[1]))          #修改后,浅拷贝的元素的id不变:2165500139912
print('%%%%%%%%%%')
print(id(copy3[1]),'\n',id(list2[1]))          #修改前的元素的id不再相等:2165500139912,2165500373416
print(list2,'\n',copy3)      #不再相同
print(list2[1] is copy3[1])  #元素不再是同一个,false

list3 = [[1, 2], (30, 40),'kkk']
deepcopy4=copy.deepcopy(list3)
print(list2[0],deepcopy4[0])
print(id(list3[0]),id(deepcopy4[0]))
list3[0].append(50)
print(list3[0],deepcopy4[0])
print(id(list3[0]),id(deepcopy4[0]))

list4 = [[1, 2], (30, 40),'kkk']
deepcopy5=copy.deepcopy(list4)
print(list4[1],deepcopy5[1])
print(id(list4[1]),id(deepcopy5[1]))

list4[1]+=(80,)

print(list4[1],deepcopy5[1])
print(id(list4[1]),id(deepcopy5[1]))

物联沃分享整理
物联沃-IOTWORD物联网 » Python中浅拷贝(copy)与深拷贝(deepcopy)的区别和用法详解

发表评论