Python 中的可變與不可變
本文將解釋 Python 中的可變與不可變。
YouTube Video
Python 中的可變與不可變
「可變」和「不可變」是指物件的可變性。理解這一點有助於避免意外的錯誤並提高內存管理效率。
什麼是可變的?
可變物件可以在創建後更改其內部狀態。
主要的可變數據類型
listdictset- 使用者定義的類別(如果其屬性可被修改)
範例:修改列表
1numbers = [1, 2, 3]
2numbers[0] = 100
3print(numbers) # [100, 2, 3]列表是一個可變物件,其元素可以自由修改。
什麼是不可變的?
不可變物件在創建後無法被更改。嘗試修改它們將導致創建一個新物件。
主要的不可變數據類型
intfloatstrtupleboolfrozenset
範例:修改字串
1text = "hello"
2# text[0] = "H" # TypeError: 'str' object does not support item assignment
3
4text = "H" + text[1:] # Creates a new string
5print(text) # "Hello"字串是不可變的,因此無法部分修改它們。
可變與不可變的比較
1# Mutable example
2a = [1, 2, 3]
3b = a
4b[0] = 100
5print(a) # [100, 2, 3] -> a is also changed
6
7# Immutable example
8x = 10
9y = x
10y = 20
11print(x) # 10 -> x is unchanged從這個例子可以看到,可變物件是以引用來共享的,所以它們可以影響到其他變數。另一方面,不可變物件在重新賦值時會創建新的實例,保持原始值不受影響。
使用 id() 檢查內部行為
在 Python 中,你可以使用 id() 函數來檢查物件的 ID。物件的 ID 類似於記憶體位址。
1# Immutable int behavior
2a = 10
3print(id(a)) # e.g., 140715920176592
4a += 1
5print(id(a)) # e.g., 140715920176624 -> ID has changed
6
7# Mutable list behavior
8b = [1, 2, 3]
9print(id(b)) # e.g., 2819127951552
10b.append(4)
11print(id(b)) # Same ID -> only the content has changed如圖所示,不可變類型會創建新的對象,而可變類型則會就地修改。
函數與可變和不可變物件的注意事項
當將可變物件傳遞給函數時,原始數據可能會被修改。
範例:修改列表的函數
1def modify_list(lst):
2 lst.append(100)
3
4my_list = [1, 2, 3]
5modify_list(my_list)
6print(my_list) # [1, 2, 3, 100]範例:修改數字的函數
另一方面,嘗試修改不可變物件會導致創建一個新的物件。
1def modify_number(n):
2 n += 10
3
4my_number = 5
5modify_number(my_number)
6print(my_number) # 5 -> unchanged實用考量
避免將可變物件用作默認參數
1# Bad example
2def add_item(item, container=[]):
3 container.append(item)
4 return container
5
6print(add_item(1)) # [1]
7print(add_item(2)) # [1, 2] -> unintended behavior
8
9# Good example
10def add_item(item, container=None):
11 if container is None:
12 container = []
13 container.append(item)
14 return container
15
16print(add_item(1)) # [1]
17print(add_item(2)) # [2]由於默認參數在函數定義時只評估一次,使用可變物件可能會導致意想不到的副作用。
- 在第一個例子中,每次呼叫
add_item都會使用同一個列表物件。當第二次呼叫add_item(2)時,先前加入的1仍在列表中,因此結果是[1, 2]。 - 在改進後的例子中,將
None作為預設值,如果參數是None,就會在函式內建立一個新的列表。這樣可以確保每次呼叫函式時都會建立一個新的列表,因此以前的結果不會影響後續的呼叫。
避免使用像列表或字典一樣的可變物件作為預設參數,應該使用 None 並在函式內部初始化它們。這是在 Python 中一項基本且重要的最佳實踐。
總結
要深入了解 Python 的變數和數據類型,掌握可變和不可變之間的區別至關重要。理解這些特性可以幫助你避免程式中的非預期行為,並撰寫更健壯且可讀性更高的程式。
您可以在我們的 YouTube 頻道上使用 Visual Studio Code 來跟隨上述文章一起學習。 請也查看我們的 YouTube 頻道。