簡介
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
淺拷貝和深拷貝的區別
淺層拷貝和深層拷貝之間的區別僅與複合對象相關:
- 一個淺層拷貝會構造一個新的複合對象,然後(在可能的範圍內)將原對象中找到的 引用插入其中。
- 一個深層拷貝會構造一個新的複合對象,然後遞歸地將原始對象中所找到的對象的 副本插入。
可變對象與不可變對象的淺拷貝和深拷貝區別:
拷貝類型 | 可變對象 | 不可變對象 |
---|---|---|
淺拷貝 | 只拷貝外層元素,不影響內層元素 | 拷貝爲新對象 |
深拷貝 | 拷貝所有元素,包括內層元素和外層元素 | 拷貝爲新對象 |