在使用 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)对应的项目(key-value 对)

  • 特点: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')(返回默认值 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' 对象没有属性 'pop'
my_tuple.pop() 

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

总结

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

  2. listdictset是各自容器类单独定义的方法

  3. 名称相同的原因是因为它们共享 “提取并返回数据” 的 约定意义

  4. 由于各类的操作方式不同,list 通过索引,dict 通过键进行移除,而 set 则是任意移除项目。