简析 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 对象分为可变对象和不可变对象。可变对象是指,对象的内容是可变的。而不可变的对象则相反,表示其内容不可变。其区分可变对象与不可变对象其实就是通过对象是否可哈希来区分的。不可变对象是可哈希类型,可变对象是不可哈希类型。

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

    扫描二维码关注公众号,回复: 9809840 查看本文章
  • 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    

浅拷贝和深拷贝的区别

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

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

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

拷贝类型 可变对象 不可变对象
浅拷贝 只拷贝外层元素,不影响内层元素 拷贝为新对象
深拷贝 拷贝所有元素,包括内层元素和外层元素 拷贝为新对象
发布了33 篇原创文章 · 获赞 62 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/Jairoguo/article/details/104526220