从新分配一块内存,建立一个新的对象,里面的元素是被拷贝对象中子元素的引用。python
import copy # L1 对象内部为两个元素: index 0 :[1,2], index 1:(100,200) L1 = [[1, 2], (100, 200)] # 对L1进行浅copy ,此时,获得一个新的List对象,并赋值给L2, L2 = list(L1) print("L1的内存地址为--{},第一个元素的地址--{},第二个元素的地址--{}".format(id(L1), id(L1[0]), id(L1[1]))) print("L2的内存地址为--{},第一个元素的地址--{},第二个元素的地址--{}".format(id(L2), id(L2[0]), id(L2[1]))) # L1的内存地址为--2581953960968,第一个元素的地址--2581953961032,第二个元素的地址--2581951586568 # L2的内存地址为--2581953936904,第一个元素的地址--2581953961032,第二个元素的地址--2581951586568 # 修改共同引用的列表的内容,因为L1,L2的第一个元素都指向这个列表,所以,L1,L2 对应的元素内容 都发生了变化,可是id是不变的。 L1[0].append(3) print(L1) # [[1, 2, 3], (100, 200)] print(L2) # [[1, 2, 3], (100, 200)] # L1 新增元素 ,L1 和L2 互相独立,不受影响 L1.append(100) print(L1) # [[1, 2, 3], (100, 200), 100] print(L2) # [[1, 2, 3], (100, 200)] # 元组不可变,所以,元组使用 + ,获得的是一个新的元祖对象,所以L2内的元组对象id不变,L1内的元组对象id发生了变化。 L1[1] += (500, 600) print(L1) # [[1, 2, 3], (100, 200, 500, 600), 100] print(L2) # [[1, 2, 3], (100, 200)] print("L1的内存地址为--{},第一个元素的地址--{},第二个元素的地址--{}".format(id(L1), id(L1[0]), id(L1[1]))) print("L2的内存地址为--{},第一个元素的地址--{},第二个元素的地址--{}".format(id(L2), id(L2[0]), id(L2[1]))) # L1的内存地址为--2581953960968,第一个元素的地址--2581953961032,第二个元素的地址--2581952542584 # L2的内存地址为--2581953936904,第一个元素的地址--2581953961032,第二个元素的地址--2581951586568 # 列表是可变的,+ 号操做,在以前基础上新增元素,相似列表的extend方法 L1[0] += [3000, 4000] print(L1) # [[1, 2, 3, 3000, 4000], (100, 200, 500, 600), 100] print(L2) # [[1, 2, 3, 3000, 4000], (100, 200)] print("L1的内存地址为--{},第一个元素的地址--{},第二个元素的地址--{}".format(id(L1), id(L1[0]), id(L1[1]))) print("L2的内存地址为--{},第一个元素的地址--{},第二个元素的地址--{}".format(id(L2), id(L2[0]), id(L2[1]))) # L1的内存地址为--2581953960968,第一个元素的地址--2581953961032,第二个元素的地址--2581952542584 # L2的内存地址为--2581953936904,第一个元素的地址--2581953961032,第二个元素的地址--2581951586568
实现方式:app
L1=[[100,200],(1000,2000)] L3=list(L1) L4=L1[:] L5=copy.copy(L1) print("L3的内存地址为--{},第一个元素的地址--{},第二个元素的地址--{}".format(id(L3), id(L3[0]), id(L3[1]))) print("L4的内存地址为--{},第一个元素的地址--{},第二个元素的地址--{}".format(id(L4), id(L4[0]), id(L4[1]))) print("L5的内存地址为--{},第一个元素的地址--{},第二个元素的地址--{}".format(id(L5), id(L5[0]), id(L5[1]))) # L3的内存地址为--2581952584392,第一个元素的地址--2581953960904,第二个元素的地址--2581951626888 # L4的内存地址为--2581953960968,第一个元素的地址--2581953960904,第二个元素的地址--2581951626888 # L5的内存地址为--2581953936968,第一个元素的地址--2581953960904,第二个元素的地址--2581951626888
s1=(100,200) s2=tuple(s1) s3=s1[:] s4=copy.copy(s1) print(id(s1)) # 2399341093128 print(id(s2)) # 2399341093128 print(id(s3)) # 2399341093128 print(id(s4)) # 2399341093128
从新分配一块内存,建立一个新对象,并将被拷贝对象中的全部元素,以递归的方式,复制到这个新对象中。新对象和原对象彻底独立,互不影响。函数
import copy L1=[[1,2],(100,200)] L2=copy.deepcopy(L1) print("L1的内存地址为--{},第一个元素的地址--{},第二个元素的地址--{}".format(id(L1), id(L1[0]), id(L1[1]))) print("L2的内存地址为--{},第一个元素的地址--{},第二个元素的地址--{}".format(id(L2), id(L2[0]), id(L2[1]))) # L1的内存地址为--1665896340552,第一个元素的地址--1665896340616,第二个元素的地址--1665893966024 # L2的内存地址为--1665896340488,第一个元素的地址--1665896340808,第二个元素的地址--1665893966024 L1[0].append(3) print(L1) # [[1, 2, 3], (100, 200)] print(L2) # [[1, 2], (100, 200)] L1.append(1000) print(L1) # [[1, 2, 3], (100, 200), 1000] print(L2) # [[1, 2], (100, 200)]
l1 = [[1, 2], (30, 40)] l2 = copy.deepcopy(l1) l1.append(100) l1[0].append(3) print(l1) # [[1, 2, 3], (30, 40), 100] print(l2) # [[1, 2], (30, 40)]
这个例子,列表 x 中有指向自身的引用,所以 x 是一个无限嵌套的列表。可是深度拷贝 x 到 y 后,程序并无出现 stack overflow 的现象。这是由于深度拷贝函数 deepcopy 中会维护一个字典,记录已经拷贝的对象与其 ID。拷贝过程当中,若是字典里已经存储了将要拷贝的对象,则会从字典直接返回。code
def deepcopy(x, memo=None, _nil=[]): """Deep copy operation on arbitrary Python objects. See the module's __doc__ string for more info. """ if memo is None: memo = {} d = id(x) # 查询被拷贝对象x的id y = memo.get(d, _nil) # 查询字典里是否已经存储了该对象 if y is not _nil: return y # 若是字典里已经存储了将要拷贝的对象,则直接返回