简介
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
变量 a
与 b
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
浅拷贝和深拷贝的区别
浅层拷贝和深层拷贝之间的区别仅与复合对象相关:
- 一个浅层拷贝会构造一个新的复合对象,然后(在可能的范围内)将原对象中找到的 引用插入其中。
- 一个深层拷贝会构造一个新的复合对象,然后递归地将原始对象中所找到的对象的 副本插入。
可变对象与不可变对象的浅拷贝和深拷贝区别:
拷贝类型 | 可变对象 | 不可变对象 |
---|---|---|
浅拷贝 | 只拷贝外层元素,不影响内层元素 | 拷贝为新对象 |
深拷贝 | 拷贝所有元素,包括内层元素和外层元素 | 拷贝为新对象 |