简析 Python 深拷贝和浅拷贝

文章目录

    • 简介
    • 了解一下
    • 浅拷贝
    • 深拷贝
    • 浅拷贝和深拷贝的区别

简介

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 深拷贝和浅拷贝_第1张图片

了解一下

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 内容一致新变量,其在内存中分别指向两个地址。

简析 Python 深拷贝和浅拷贝_第2张图片

深拷贝

先看个例子:

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 只拷贝的最外层的内容,而内层的内容是直接引用的。另外,像这种列表中引用另一个列表的的形式,被称为复合对象。更准确的说,包含其他对象的对象就是复合对象。

简析 Python 深拷贝和浅拷贝_第3张图片

如果想将内层的内容也作为新变量的一部分,需要用到标准库 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    

简析 Python 深拷贝和浅拷贝_第4张图片

浅拷贝和深拷贝的区别

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

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

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

拷贝类型 可变对象 不可变对象
浅拷贝 只拷贝外层元素,不影响内层元素 拷贝为新对象
深拷贝 拷贝所有元素,包括内层元素和外层元素 拷贝为新对象

你可能感兴趣的:(All,Python)