深浅copy

深浅copy对比

列表赋值

例如:列表a=[‘a’, 'b', 'c', 'd', 1, 2, 3],当执行代码b=a,可以得到b=[‘a’, 'b', 'c', 'd', 1, 2, 3],具体实现如下:

>>> a=['a', 'b', 'c', 'd', 1, 2, 3]
>>> b=a
>>> id(a),id(b)
(2805890045000, 2805890045000)

可以看出来,这里两个列表a和b的内存地址是一样的,那么当我们改变列表a中的某一个元素时,b列表会发生什么结果呢?

>>> a[0]='jersey'
>>> a
['jersey', 'b', 'c', 'd', 1, 2, 3]
>>> b
['jersey', 'b', 'c', 'd', 1, 2, 3]
>>> id(a),id(a[0]),id(b),id(b[0])
(2805890045000, 2805890018920, 2805890045000, 2805890018920)

我们可以看到id(a)和id(b)是一样的,id(a[0])和id(b[0])也是一样的。这意味着,当我们将变量b指向a列表时,b列表和a列表共享同一个内存地址,那么当列表a中的元素发生了变化,那么共享该内存地址的列表b里面的元素也是同时发生变化。

浅copy

那么有没有方式,能够像字符变量那样,当改变第一个变量的时候,第二个变量不受影响呢?如下程序所示,当将a的值赋给b后,在改变a,b的值并不会收到任何的影响:

>>> a=1
>>> b=a
>>> b
1
>>> a=2
>>> a,b
(2, 1)

这里,我们就要了解为什么会这样?其实赋值并不是说把变量改变了。我们知道:

  1. a=1,计算机实际上是开辟了一个内存地址,把1放进去,让后让变量指向该1的内存地址;
  2. b=a,实际上是将变量b同时指向1的内存地址;
  3. 当进行到第三步a=2的时候,计算机是重新开辟了一块新的内存地址,将2放入其中,让a指向这个新的内存地址。然而,b指向的内存地址仍旧为1的内存地址,所以没有发生改变。

同理可得,那我们如果实现可以改变列表中的某个元素的功能,实际上就是需要让两个列表的内存地址是不同的,那么在修改的时候,就互不干扰。这里就可以引出.copy()操作符。如下面代码所示:

>>> a=['a', 'b', 'c', 'd', 1, 2, 3]
>>> b=a.copy()
>>> b
['a', 'b', 'c', 'd', 1, 2, 3]
>>> a[0]='A'
>>> a
['A', 'b', 'c', 'd', 1, 2, 3]
>>> b
['a', 'b', 'c', 'd', 1, 2, 3]

不难发现,当改变a列表中第一个元素的值的时候,b列表没有发生任何改变,这就是因为通过.copy()这个操作符,其实是计算机开辟了一个新的id,将a列表赋值到这个新的id上,让变量b指向这个id,那么当改变a中的元素也就和b列表没有什么关系了~

深copy

那么,当我们在一个列表里面,嵌套一个新的列表会发生什么情况呢?让我们先看看代码实现吧~

>>> a = ['alex', 'shanshan', 24, ['longting', 22]]
>>> b=a.copy()
>>> b
['alex', 'shanshan', 24, ['longting', 22]]
>>> a[3][0]='jersey'
>>> a
['alex', 'shanshan', 24, ['jersey', 22]]
>>> b
['alex', 'shanshan', 24, ['jersey', 22]]

我们看的出来,当嵌套的新列表里面的元素发生了改变之后,按理来说不应该发生变化的b列表,却同使发生了变化~这是为什么呢?
通过我们上面浅copy中的分析,如果两个列表是指向同一个内存地址,那么当一个列表发生变化的时候,那么另外一个就会发生变化,那么现在就让我们来验证一下这两个嵌套的新列表的id吧~

>>> id(a[3]),id(b[3])
(2805890044744, 2805890044744)

我们发现,正如我们所料,它们两个嵌套的新列表指向的是同一个内存地址。这表明,当最外层的列表(本示例中为a)进行copy的时候,只是开辟了一个新的内存地址,并将当前列表复制进去,让新的变量(本示例中为b)指向这个内存地址。然而,却没有给嵌套的列表开辟新的内存地址,因此,这两个列表中的嵌套列表仍为共享同一个地址,所以某一个列表中元素发生变化的时候,另外一个同时发生变化。

这个时候就需要引出深度复制的概念:也就是当复制的时候,连同里面的嵌套,也一同开辟新的内存地址进行复制,两个列表完全独立,互不干扰,一个发生变化的时候,第二个不发生任何变化。但是不建议这么操作,因为极其占用内存!!~~操作码为:copy.deepcopy(列表名)

猜你喜欢

转载自www.cnblogs.com/GGGGGGZX/p/8911611.html