为每种需求挑选合适的结构:不可变的元组、用于 O(1) 成员检测的集合,以及应对常见模式的 Counter 和 defaultdict。
在 Kodokon 中打开本课选对数据结构,可以一举解决可读性和性能两个问题。元组是一个不可变的序列:非常适合表示固定长度的异构记录(坐标、一对键值)。不可变意味着可哈希(前提是它的内容也可哈希):因此元组可以充当字典的键或集合的元素,而列表则不行。解包让代码富有表现力 - 而一个 "返回多个值" 的函数,实际上返回的是一个元组。
point = (48.85, 2.35)
lat, lon = point
def min_max(values):
return min(values), max(values)
low, high = min_max([3, 1, 4, 1, 5])
print(low, high)
distances = {("paris", "lyon"): 465}
print(distances[("paris", "lyon")])集合保证元素唯一,并提供平均 O(1) 的成员检测,而列表则是 O(n)。在一个要执行成千上万次 x in collection 检查的循环里,差距会立刻显现出来。集合运算符(& 交集、- 差集、| 并集)相比嵌套循环是一次真正的升级:比较两份标识符列表 - 谁消失了、谁是新来的 - 两行代码就够了。
active = {"ada", "linus", "guido"}
banned = {"linus", "mallory"}
print(active & banned)
print(active - banned)
print(active | banned)
emails = ["a@x.io", "b@x.io", "a@x.io"]
unique = set(emails)
print(len(unique))collections 模块覆盖了两个日常需求。Counter 统计可迭代对象中各元素出现的次数,并提供 most_common(n) - 再也不用手写计数字典了。defaultdict(factory) 会在需要时即时构造缺失的值:defaultdict(list) 是按键分组元素的标准工具,无需在循环的每一轮里都检测键是否存在。
from collections import Counter, defaultdict
words = ["go", "py", "go", "rs", "go"]
counts = Counter(words)
print(counts.most_common(2))
groups = defaultdict(list)
pairs = [("fr", "Ada"), ("us", "Lin"), ("fr", "Zoe")]
for country, name in pairs:
groups[country].append(name)
print(dict(groups))