Python3 深拷贝和浅拷贝的区别和原理

首先,我们知道在 Python3 中,有 6 个标准的数据类型,他们又分为可变和不可变

不可变数据类型(3个)

  • Number(数字)

  • String(字符串)

  • Tuple(元组)

可变数据类型(3个)

  • List(列表)

  • Dictionary(字典)

  • Set(集合)

在 Python 中,其实是没有那种传统意义上的变量,我们通常说的变量其实是一个标签,或者是一个指针变量,因为它保存的是变量的一个地址

对于不可变类型,赋值、浅拷贝、深拷贝其实都是创建一个标签,指向了变量的地址,它的 id 都是一样的。而当我们改变其中一个标签的值的时候,其实就是将这个标签重新指向一个新的地址,旧的变量的引用计数会减一,随之它的 id 也会变化

In [1]: from copy import copy, deepcopy

In [2]: a = 'a, b, c, d'

In [3]: b = a

In [4]: c = copy(a)

In [5]: d = deepcopy(a)

In [6]: a, b, c, d
Out[6]: ('a, b, c, d', 'a, b, c, d', 'a, b, c, d', 'a, b, c, d')

In [7]: id(a), id(b), id(c), id(d)
Out[7]: (4592638320, 4592638320, 4592638320, 4592638320)

In [8]: a = '1, 2, 3, 4'

In [9]: a, b, c, d
Out[9]: ('1, 2, 3, 4', 'a, b, c, d', 'a, b, c, d', 'a, b, c, d')

In [10]: id(a), id(b), id(c), id(d)
Out[10]: (4592787504, 4592638320, 4592638320, 4592638320)

对于可变类型,赋值是创建一个标签,和不可变类型一致

浅拷贝的时候,标签会重新开辟一个新的地址,不占用被拷贝对象的引用计数。新的标签也是指向变量(或者叫数组)的地址,它们 id 是不同的

深拷贝的时候,标签会重新开辟一个新的地址,并将被拷贝的对象放入新的地址。此时,内存地址中就会有两份一模一样的数据,但是地址不同, 当然,它们 id 也是不同的

In [1]: from copy import copy, deepcopy

In [2]: a = [1, [2, 3], '4']

In [3]: b = a

In [4]: c = copy(a)

In [5]: d = deepcopy(a)

In [6]: a, b, c, d
Out[6]: ([1, [2, 3], '4'], [1, [2, 3], '4'], [1, [2, 3], '4'], [1, [2, 3], '4'])

In [7]: id(a), id(b), id(c), id(d)
Out[7]: (4394796232, 4394796232, 4397213000, 4397312072)

In [8]: a[1][0] = 0

In [9]: a, b, c, d
Out[9]: ([1, [0, 3], '4'], [1, [0, 3], '4'], [1, [0, 3], '4'], [1, [2, 3], '4'])

In [10]: id(a), id(b), id(c), id(d)
Out[10]: (4394796232, 4394796232, 4397213000, 4397312072)

有一点需要注意的是,当我们重新给不可变类型的标签赋值时,它会释放标签的引用计数,并且改变它的地址。但是下列第 11 行代码,我将它的标签重新赋值后,它的地址还是没变(13行),这是为什么呢?

In [11]: a[0] = 0

In [12]: a, b, c, d
Out[12]: ([0, [0, 3], '4'], [0, [0, 3], '4'], [1, [0, 3], '4'], [1, [2, 3], '4'])

In [13]: id(a), id(b), id(c), id(d)
Out[13]: (4394796232, 4394796232, 4397213000, 4397312072)

这是因为刚刚我们查看的是整个数组的 id,而不是某一个元素的 id

重新给数组中的某一个元素赋值,当我们单独查看它的 id 时,它的 id 已经发生了变化(14,17行)

In [14]: id(a[0])
Out[14]: 4365118432

In [15]: a[0] = 5

In [16]: id(a), id(b), id(c), id(d)
Out[16]: (4394796232, 4394796232, 4397213000, 4397312072)

In [17]: id(a[0])
Out[17]: 4365118592

对于 Python 的浅拷贝和深拷贝其实是针对于那些可变类型的,因为对不可变类型没有意义,赋值操作就足够了

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值