七八层 if-else 嵌套、好几个临时列表来回倒腾数据、为了统计几个元素还手动维护了一个计数器字典……很多代码之所以又长又丑又慢,不是因为需求复杂,而是因为对 Python 内置数据结构不熟悉。
1. 用 dict.get 提供默认值
很多教程会教你这么写:
config = {'host': 'localhost'}if 'port' in config: port = config['port']else: port = 8080
试试这个:
config = {'host': 'localhost'}port = config.get('port', 8080)print(port) # 8080
dict.get(key, default) 在键不存在时返回默认值而不是抛 KeyError,一行代码替代 if-else 判断,是字典取值的标准姿势。
2. 用 dict 合并运算符 |
最常见的写法大概是这样的:
default = {'color': 'red', 'size': 10}custom = {'size': 20, 'weight': 5}result = {**default, **custom}
老手一般这么写:
default = {'color': 'red', 'size': 10}custom = {'size': 20, 'weight': 5}result = default | custom # Python 3.9+print(result) # {'color': 'red', 'size': 20, 'weight': 5}
Python 3.9+ 引入字典合并运算符 |,语法更直观。
|= 可以原地更新。右侧字典的值会覆盖左侧同名键。
3. 用 collections.Counter 统计频次
很多人统计词频是这么写的:
words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']counts = {}for w in words: counts[w] = counts.get(w, 0) + 1print(counts)
换成这样就优雅多了:
from collections import Counterwords = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']counts = Counter(words)print(counts.most_common(2)) # [('apple', 3), ('banana', 2)]
Counter 是专门用于计数的字典子类,自带 most_common、elements 等实用方法,还支持加减运算,是频次统计的利器。
4. 用 heapq 实现优先队列
看起来没问题,但其实有更好的方式:
tasks = [(3, 'low'), (1, 'high'), (2, 'mid')]tasks.sort() # 每次插入都要重新排序 O(n log n)print(tasks[0])
其实标准库早就有答案了:
import heapqtasks = []heapq.heappush(tasks, (3, 'low'))heapq.heappush(tasks, (1, 'high'))heapq.heappush(tasks, (2, 'mid'))print(heapq.heappop(tasks)) # (1, 'high')print(heapq.nsmallest(2, tasks)) # 最小的2个
heapq 实现了最小堆,插入和弹出都是 O(log n),比每次排序 O(n log n) 高效得多,是实现优先队列的标准方案。
5. 用 bisect 维护有序列表
刚学 Python 的时候我这么写过:
sorted_list = [1, 3, 5, 7, 9]sorted_list.append(4)sorted_list.sort() # O(n log n)
一行代码就能搞定:
import bisectsorted_list = [1, 3, 5, 7, 9]bisect.insort(sorted_list, 4) # O(n) 插入print(sorted_list) # [1, 3, 4, 5, 7, 9]idx = bisect.bisect_left(sorted_list, 5) # O(log n) 查找print(idx) # 3
bisect 模块用二分查找维护有序列表,insort 插入后自动保持有序,比 append+sort 更高效,适合需要频繁插入的有序序列场景。
速查表
| 场景 | 别这样写 | 试试这样 |
|---|
| 字典取值带默认值 | if/else 判断键是否存在 | d.get(key, default) |
| 合并两个字典 | {**d1, **d2} | `d1 |
| 统计词频/频次 | 手动循环计数 | Counter(words).most_common(n) |
| 优先队列 | 列表 + sort | heapq.heappush/pop |
| 维护有序列表 | append + sort | bisect.insort(list, val) |
优雅的代码从来不是炫技,而是恰到好处。
当你不再用手动循环去凑一个计数器,当你的队列不再因为 pop(0) 而慢如蜗牛,当你的字典取值再也不用写满屏的 if key not in:
你会发现,代码变短了,思路变清晰了,连 Bug 都躲着你走了。
关于作者
写了 10 年 Python,赶上了机器学习的热潮,又撞上了大模型的浪头,每次以为学明白了,行业又变了一次。
把自己踩过的坑、走过的弯路、看过的热闹,说给还在路上的人听。
关注「鲁叶的Python」,第一时间接收技术干货。