python对于复制操作并不是大家想的那么简单,有时候会根据需求来完成自己的操作,上一篇文章已经讲了引用机制在此基础上我们进行论述:
首先我们定义一个列表L1:l1 = ["egom","lxx",[1,2]] 复制完成后L1为父列表,l为子列表,此时我们有这几种需求:1.对父列表中元素进行改变,子列表同时改变;2.对父列表中元素进行改变,子列表不改变;那么我们如何实现?
首先明白一点:可变类型和不可变类型:
可变类型:列表,字典(值改变,id不变)
不可变类型:int float str bool (值改变,id改变)
向列表赋值时之只能对可变类型产生影响,
一般来说复制操作有三种:第一种就是简单的引用:l=l1;无需任何解释
第二种是浅拷贝:l=l1.copy()浅拷贝达到的效果是对父列表中元素进行改变,子列表同时改变进行如下操作:

l1 = [
      "egom",
      "lxx",
      [1,2]
]
l=l1.copy()#浅拷贝
l1[2][1]=[111]#对l1中第三个元素:列表的第一个元素进行修改
l1.append(3)#对l1进行添加值操作
print(l1)
print(l)
print(id(l1[2]),id(l1[3]))#打印l1中第三个元素的id(身份值)和第四个元素的id
print(id(l[2]))#打印l中第三个元素的id

按照浅拷贝的效果来说:l中应该没有第四个元素(3);l1中第三个元素的id(身份值)与l中第三个元素的id(身份值)相等
打印结果:

['egom', 'lxx', [1, [111]], 3]
['egom', 'lxx', [1, [111]]]
2078224515016 140734188200400
2078224515016

由id值可以验证确实指向的是同一个对象,结果确实相同。接下来给出原因:列表中都是存储的元素的地址,再由地址指向元素

python复制矩阵除了最后一列_python


在l对l1进行复制操作时,我们可以看到赋值的并不是对象本身,而是对象的引用,再有引用指向对象本身。就像找路一样,从来不会挨个每条路去看,而是找到具体位置在哪里,这样更方便查找。这就类似于指针 指向的永远是地址,在浅拷贝中由于只是复制地址,前后都指向同一个容器,所以对父列表中可变类型进行改变,字列表也会改变,但不可变类型不改变。

再看深拷贝:进行如下操作

import copy#首先需要导入库
l1 = [
      "egom",
      "lxx",
      [1,2]
] 
l=copy.deepcopy(l1)#进行深拷贝
l1[2][1]=[1]#把l1中第三个元素中的第二个元素变为[1]
print(l1,l)
print(id(l[0]),id(l[2]))
print(id(l1[0]),id(l1[2]))

按照深拷贝的效果来说:对父列表进行改变,子列表应该保持不变;

['egom', 'lxx', [1, [1]]] ['egom', 'lxx', [1, 2]]
2078224658736 2078224624328
2078224658736 2078224267784
此时可以看到对l1进行改变 l并没有发生变化。在打印不可变类型时id值不变 打印可变类型时id值发生改变

python复制矩阵除了最后一列_深拷贝_02


可以看出深拷贝相当于重新创造了一个新的容器,对于不可变类型时还是值指向的同一个元素,只不过引用发生了改变,这一点从id值可以看出,对于可变类型,创造了新的容器来容纳新的地址,但新的地址最后指向的还是相同的对象。这就是列表对可变类型进行改变,新列表不变,二者独立,列表id改变

一句话总结:拷贝对于不可变的继续引用,对于可变的重新造一个容器进行引用,所以id改变 对于可变类型浅拷贝前后都指向同样的容器,所以id不变