简析 Python 深拷贝和浅拷贝

14 篇文章 1 订阅

简介

Python 中赋值语句不复制对象,而是在目标和对象之间创建绑定 (Bindings) 关系。

示例:

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

In [2]: b = a

In [3]: a
Out[3]: [1, 2, 3]

In [4]: b
Out[4]: [1, 2, 3]

In [5]: id(a)
Out[5]: 87660264

In [6]: id(b)
Out[6]: 87660264

变量 ab id 相同,也就说明他们指向同一地址,b 重复的引用了 a 指向的这个对象。

了解一下

Python 对象分为可变对象和不可变对象。可变对象是指,对象的内容是可变的。而不可变的对象则相反,表示其内容不可变。其区分可变对象与不可变对象其实就是通过对象是否可哈希来区分的。不可变对象是可哈希类型,可变对象是不可哈希类型。

In [1]: hash(1)
Out[1]: 1

In [2]: hash(1.5)
Out[2]: 1073741825

In [3]: hash(True)
Out[3]: 1

In [4]: hash("123")
Out[4]: 2090756218

In [5]: hash((1,2,3))
Out[5]: -2022708474

In [6]: hash([1,2,3])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-35e31e935e9e> in <module>
----> 1 hash([1,2,3])

TypeError: unhashable type: 'list'

In [7]: hash({1,2,3})
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-7-d5ba4eb1a90a> in <module>
----> 1 hash({1,2,3})

TypeError: unhashable type: 'set'

In [8]: hash({"A": 1})
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-3d5562cfa16c> in <module>
----> 1 hash({"A": 1})

TypeError: unhashable type: 'dict'

内置类型不可变对象包括:

  • int

  • float

  • bool

  • str

  • tuple

  • frozenset

内置类型可变对象包括:

  • list

  • set

  • dict

浅拷贝

当我们想通过赋值来获得一个新的对象,Python 给我们提供了一个方法 copy() ,通过此方法赋值的方式称为浅拷贝或浅层拷贝。

示例:

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

In [2]: b = a.copy()

In [3]: a
Out[3]: [1, 2, 3]

In [4]: b
Out[4]: [1, 2, 3]

In [5]: id(a)
Out[5]: 82380744

In [6]: id(b)
Out[6]: 85989288

In [7]: a.append(4)

In [8]: a
Out[8]: [1, 2, 3, 4]

In [9]: b
Out[9]: [1, 2, 3]

这样我们会获得一个与 a 内容一致新变量,其在内存中分别指向两个地址。

深拷贝

先看个例子:

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

In [2]: b = a.copy()

In [3]: a[2].append(5)

In [4]: a.append(6)

In [5]: a
Out[5]: [1, 2, [3, 4, 5], 6]

In [6]: b
Out[6]: [1, 2, [3, 4, 5]]
    
In [7]: id(a[2])
Out[7]: 80479944

In [8]: id(b[2])
Out[8]: 80479944

这并没有真正的新变量,b 只拷贝的最外层的内容,而内层的内容是直接引用的。另外,像这种列表中引用另一个列表的的形式,被称为复合对象。更准确的说,包含其他对象的对象就是复合对象。

如果想将内层的内容也作为新变量的一部分,需要用到标准库 copy 中的 deepcopy() 方法,通过此方法赋值的方式称为深拷贝或深层拷贝。

示例:

In [1]: import copy

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

In [3]: b = copy.deepcopy(a)

In [4]: a[2].append(5)

In [5]: a.append(6)

In [6]: a
Out[6]: [1, 2, [3, 4, 5], 6]

In [7]: b
Out[7]: [1, 2, [3, 4]]
    
In [8]: id(a[2])
Out[8]: 75039880

In [9]: id(b[2])
Out[9]: 78604328    

浅拷贝和深拷贝的区别

浅层拷贝和深层拷贝之间的区别仅与复合对象相关:

  • 一个浅层拷贝会构造一个新的复合对象,然后(在可能的范围内)将原对象中找到的 引用插入其中。
  • 一个深层拷贝会构造一个新的复合对象,然后递归地将原始对象中所找到的对象的 副本插入。

可变对象与不可变对象的浅拷贝和深拷贝区别:

拷贝类型可变对象不可变对象
浅拷贝只拷贝外层元素,不影响内层元素拷贝为新对象
深拷贝拷贝所有元素,包括内层元素和外层元素拷贝为新对象
  • 30
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值