Python 之所以强大和流行,其内置的、设计精良的数据结构功不可没。它们是构建任何程序的基础模块。
序列类型 —— 有序数据的世界#
序列是 Python 中最基本的数据结构类型,它们的共同特点是其成员有序排列,可以通过索引访问。列表和元组是序列类型的两大核心。
列表 (List): 动态、可变#
列表是 Python 中最灵活的序列类型,它是一个可变的、有序的元素集合。你可以随时添加、删除或修改其中的元素。
核心特性与常用方法:
- 增删改查:
append(x): 在末尾添加。extend(iterable): 合并另一个序列。insert(i, x): 在指定索引i处插入。remove(x): 按值删除第一个匹配项。pop([i]): 按索引i(默认为末尾) 移除并返回该元素。
- 排序与反转:
sort(): 原地排序。reverse(): 原地反转。
- 其他:
copy(): 返回列表的浅拷贝。count(x): 统计元素x出现的次数。
代码实践:
# 初始化与基本操作
fruits = ['orange', 'apple', 'pear', 'banana']
fruits.append('grape') # 添加
fruits[1] = 'green apple' # 修改
print(fruits) # ['orange', 'green apple', 'pear', 'banana', 'grape']
# 列表作为堆栈 (LIFO)
stack = [3, 4, 5]
stack.append(6) # 入栈
stack.pop() # 出栈 -> 返回 6
# 列表作为队列 (FIFO) - 效率低,推荐使用 collections.deque
from collections import deque
queue = deque(["Eric", "John"])
queue.append("Terry") # 入队
queue.popleft() # 高效出队 -> 返回 'Eric'
关键技巧:列表推导式
列表推导式是 Python 的一大特色,它提供了一种极其优雅和简洁的方式来创建列表。
# 传统方式
squares = []
for x in range(10):
squares.append(x**2)
# 列表推导式
squares = [x**2 for x in range(10)]
# -> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 加入条件判断
even_squares = [x**2 for x in range(10) if x % 2 == 0]
# -> [0, 4, 16, 36, 64]
元组 (Tuple): 不变#
元组与列表类似,也是一个有序的序列,但其核心特性是不可变。一旦创建,元组的内容就无法被修改。
核心特性与应用场景:
- 不可变性: 保证了数据的完整性,使其可以作为字典的键或集合的元素。
- 序列解包: 这是元组最优雅的特性之一,可以用于变量赋值、函数返回等。
- 性能: 通常情况下,元组比列表占用更少的内存,处理速度也稍快。
代码实践:
# 创建元组 (注意单元素元组需要一个逗号)
t = 123, 'hello', True
singleton = ('world',)
# 序列解包
x, y, z = t
print(f"x={x}, y={y}, z={z}") # x=123, y=hello, z=True
# 作为字典的键
location_data = {
(39.9042, 116.4074): "Beijing",
(31.2304, 121.4737): "Shanghai"
}
# 尝试修改元组会引发 TypeError
# t[0] = 456 # -> TypeError: 'tuple' object does not support item assignment
集合与映射 —— 无序但高效#
与序列类型不同,这一类数据结构通常不依赖于元素的顺序,而是通过唯一的键或成员关系来组织数据。
集合 (Set): 高效、唯一#
集合是一个无序、不含重复元素的容器。它的基本用法包括成员检测、消除重复元素。集合对象支持合集、交集、差集、对称差分等数学运算。
核心特性与操作:
- 唯一性: 自动去除重复元素。
- 成员测试:
in操作的效率远高于列表。 - 集合运算:
|或union(): 并集&或intersection(): 交集-或difference(): 差集^或symmetric_difference(): 对称差集
代码实践:
# 创建与去重
basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
print(basket) # {'banana', 'pear', 'apple', 'orange'} (顺序不固定)
# 成员测试
print('orange' in basket) # True
# 集合运算
a = set('abracadabra')
b = set('alacazam')
print(f"Difference (a - b): {a - b}") # {'r', 'b', 'd'}
print(f"Union (a | b): {a | b}") # {'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
# 与列表推导式类似,集合也支持推导式
unique_consonants = {c for c in 'programming' if c not in 'aeiou'}
print(unique_consonants) # {'p', 'r', 'g', 'm', 'n'}
📌 最佳实践: 当你需要对一个列表进行快速去重时,list(set(original_list)) 是最高效的方法。
字典 (Dictionary): 灵活映射#
字典是 Python 的主力数据结构,它存储的是键-值 (key-value) 对。每个键必须是唯一的且不可变的。自 Python 3.7 起,字典会保持元素的插入顺序。
核心特性与操作:
- 快速查找: 通过键来索引值,时间复杂度接近 O(1)。
- 动态性: 可以随时添加、修改或删除键值对。
- 常用方法:
get(key, default): 安全地获取值,若键不存在则返回default值(默认为None)。keys(): 返回所有键的视图。values(): 返回所有值的视图。items(): 返回所有 (键, 值) 对的视图,常用于循环。
代码实践:
# 创建字典
tel = {'jack': 4098, 'sape': 4139}
tel['guido'] = 4127 # 添加新条目
print(tel) # {'jack': 4098, 'sape': 4139, 'guido': 4127}
# 安全访问
print(tel.get('sape')) # 4139
print(tel.get('non_exist')) # None
# 字典推导式
power_of_two = {x: 2**x for x in range(5)}
print(power_of_two) # {0: 1, 1: 2, 2: 4, 3: 8, 4: 16}
操作数据结构的通用技巧#
掌握了数据结构本身后,我们还需要一些通用的“招式”来高效地操作它们。
del 语句:通用的删除利器#
del 是一个通用的 Python 语句 (Statement),而非特定数据结构的方法 (Method)。它的适用范围非常广泛,是 Python 语言核心语法的一部分,其核心作用是“解除绑定”——即移除一个名称与一个对象之间的关联。
- 删除列表元素或切片:
del my_list[0],del my_list[2:5] - 删除字典键值对:
del my_dict['key'] - 删除整个变量:
del my_variable(从命名空间中移除)
辨析 del, .pop(), 和 .remove()
| 操作方式 | del list[i] | list.pop(i) | list.remove(value) |
|---|---|---|---|
| 作用目标 | 索引或切片 | 索引 (默认为-1) | 第一个匹配的值 |
| 返回值 | None (无) | 被删除的元素 | None (无) |
| 核心场景 | 静默地删除,不关心其值。 | 需要使用被删除的元素。 | 只知道值,不知道位置。 |
更 Pythonic 的遍历#
Python 提供了多种优雅的循环技巧,让代码更具可读性。
遍历字典: 使用
.items()同时获取键和值。knights = {'gallahad': 'the pure', 'robin': 'the brave'} for k, v in knights.items(): print(k, v)遍历序列时获取索引: 使用
enumerate()。for i, v in enumerate(['tic', 'tac', 'toe']): print(i, v) # 0 tic, 1 tac, 2 toe同时遍历多个序列: 使用
zip()将它们“拉”在一起。questions = ['name', 'quest', 'color'] answers = ['lancelot', 'the holy grail', 'blue'] for q, a in zip(questions, answers): print(f'What is your {q}? It is {a}.')
总结:选择正确的工具#
选择哪种数据结构,取决于具体需求。下面是一个快速参考:
| 数据结构 | 可变性 (Mutable) | 有序性 (Ordered) | 唯一性 (Unique) | 核心用途 |
|---|---|---|---|---|
| 列表 (List) | ✅ 是 | ✅ 是 | ❌否 | 通用、灵活的元素序列 |
| 元组 (Tuple) | ❌否 | ✅ 是 | ❌否 | 不可变的数据记录,用作键 |
| 集合 (Set) | ✅ 是 | ❌否 | ✅ 是 | 去重、成员测试、数学运算 |
| 字典 (Dict) | ✅ 是 | ✅ 是 (自 3.7) | 键唯一 | 存储键值对,快速查找 |