在使用 Python 的時候,你會發現自己在使用 my_list.pop() 來刪除列表的最後一項,以及用 my_dict.pop('key') 刪除字典的項目,無論何種對象,都是在使用 .pop()

有時 pop() 感覺就像是可以附加到任何對象上的 萬能實例方法。那麼這 pop() 方法的本質是什麼呢?


1. 'pop()' 不是一個



簡單來說,listpop()dictpop() 名字相同,但實際上是完全不同的方法

  • list 類別為列表定義了專屬的 pop() 方法。

  • dict 類別同樣為字典定義了專屬的 pop() 方法。

  • set 類別也是如此。

擁有相同名字的方法的不同對象之所以能這樣,是因為 Python 的物件導向特性之一——多型性 (Polymorphism)。名稱 'pop' 只是共享了 "從資料結構中提取並返回一個項目 (pop)" 的傳統意義。


2. 各類別的 pop() 不同的運作方式

雖然名稱相同,但其運作方式並不相同。每個類別都是針對自己的資料結構實現了 pop()

1. list.pop([index])

  • 運作: 從列表中 移除並返回某個特定索引 (index) 的項目

  • 特性: 如果沒有指定索引,預設為 -1,將移除 最後一項。這與堆疊(Stack)資料結構的 'pop' 操作相同。

  • 範例:

my_list = ['a', 'b', 'c']

# 不指定索引(移除最後一項 'c')
last_item = my_list.pop()
print(f"返回的值: {last_item}, 剩餘列表: {my_list}")
# 輸出: 返回的值: c, 剩餘列表: ['a', 'b']

# 指定索引 0(移除 'a')
first_item = my_list.pop(0)
print(f"返回的值: {first_item}, 剩餘列表: {my_list}")
# 輸出: 返回的值: a, 剩餘列表: ['b']

2. dict.pop(key[, default])

  • 運作: 從字典中 移除並返回對應某個特定鍵 (key) 的項目 (鍵值對)

  • 特性: 不同於 list.pop(),此方法必須傳遞 鍵 (key),而不是索引。如果鍵不存在且給定了 default 值,則返回該值;如果沒有給定 default 值,將引發 KeyError

  • 範例:

my_dict = {'apple': 1, 'banana': 2}

# 移除 'apple' 鍵
item = my_dict.pop('apple')
print(f"返回的值: {item}, 剩餘字典: {my_dict}")
# 輸出: 返回的值: 1, 剩餘字典: {'banana': 2}

# 嘗試刪除不存在的鍵 ('grape')(返回 default 值 99)
default_item = my_dict.pop('grape', 99)
print(f"返回的值: {default_item}, 剩餘字典: {my_dict}")
# 輸出: 返回的值: 99, 剩餘字典: {'banana': 2}

3. set.pop()

  • 運作: 從集合 (set) 中 隨機移除一個項目並返回該項目

  • 特性: 集合是無序的資料結構,因此無法預測將移除哪個項目。pop() 不接受任何參數。

  • 範例:

my_set = {10, 20, 30}

# 隨機移除一項(不知結果為何)
item = my_set.pop()
print(f"返回的值: {item}, 剩餘集合: {my_set}")
# 可能的輸出 1: 返回的值: 10, 剩餘集合: {20, 30}
# 可能的輸出 2: 返回的值: 20, 剩餘集合: {10, 30}

3. 為何看起來 "無所不在"



我們在使用 pop() 時,覺得它像 "實例方法",這是正確的。pop() 確實是每個對象(實例)所擁有的方法。

看似 obj.pop() 的情況並不意味著 pop() 是全局函數,或是定義在所有對象的父類別中的方法。當 Python 調用 obj.method() 時,會動態檢查 obj 這個對象是否擁有名稱為 method 的屬性(方法)。

  • my_listlist 類的實例,list 類定義了 pop

  • my_dictdict 類的實例,dict 類也定義了 pop

因此 my_list.pop()my_dict.pop() 都可以正常工作。

如果在未定義 pop() 方法的對象上嘗試調用,結果會如何?如預期,會引發 AttributeError。以元組為例。

# 元組(tuple) 不能更改項目,因此沒有 pop() 方法。
my_tuple = (1, 2, 3)

# AttributeError: 'tuple' object has no attribute 'pop'
my_tuple.pop() 

An infographic illustrating the pop() method in Python across three data structures

總結

  1. pop() 不是 Python 的全局函數或共通方法。

  2. listdictset都是各自容器類別獨立定義的方法

  3. 它們同名是因為 "提取數據並返回" 的 習慣性 (convention) 意義。

  4. 由於每個類別的運作方式不同,list 依據索引,dict 依據鍵,set 隨機移除項目。