随手记录一些做项目和准备面试时会用到的 Python 小模式。
Decorators for Cross-Cutting Concerns
项目里经常有几类逻辑散落在不同函数中:
- logging
- timing
- permission checks
- retries
- validation
For example:
import time
def load_data():
start = time.time()
# actual work
# ...
print(f"load_data took {time.time() - start:.2f}s")把它们直接写进业务函数,很快就会重复,也会遮住真正的业务逻辑。
用 decorator 收口
用 decorator 把这类附加逻辑从业务函数里拿出来。
import time
from functools import wraps
def timeit(func):
# @wraps for identity and introspection
@wraps(func)
def wrapper(*args, **kwargs):
# before code block
start = time.time()
# func
result = func(*args, **kwargs)
# after code block
duration = time.time() - start
print(f"{func.__name__} took {duration:.2f}s")
return result
return wrapper使用时:
@timeit
def load_data():
# ...这样做的好处
- 业务函数只保留自己的工作
- 同一套逻辑可以复用到多个函数
- 要调整或移除时有一个明确入口
Decorators are a practical way to implement cross-cutting concerns without polluting core logic. 写 decorator 时记得使用 functools.wraps,保留原函数的 metadata,避免影响 introspection 和 framework。
Progress Bars with tqdm
耗时循环如果没有反馈,跑到一半很难判断进度。
For example:
for i in range(1000000):
process(i)处理大数据集或训练模型时,通常想知道:
- how much work is done
- how long it will take
- whether the program is stuck
手动加日志既吵,也不容易看出整体进度。
加上 tqdm
tqdm 可以加一条轻量进度条。
from tqdm import tqdm
for i in tqdm(range(1000000)):
process(i)它会显示:
- 完成百分比
- 迭代速度
- 预计剩余时间
输出大致如下:
45%|██████████▌ | 450000/1000000 [00:03<00:04, 120k it/s]
使用场景
- 改动很小
- 适用于 iterable、list、generator 和 pandas
配合 pandas:
from tqdm import tqdm
tqdm.pandas()
df["result"] = df["data"].progress_apply(process)循环会占用明显时间时就加 tqdm。做数据处理或实验时,一条进度条就能省掉很多等待中的猜测。
Collections Utilities (defaultdict, Counter, deque)
计数、分组和队列这类常见操作,用普通 dict 往往要写不少初始化代码。
例如计数:
counts = {}
for word in words:
if word not in counts:
counts[word] = 0
counts[word] += 1
分组也会反复检查 key 是否存在:
groups = {}
for k, v in pairs:
if k not in groups:
groups[k] = []
groups[k].append(v)直接用 collections
collections 已经提供了对应工具。
计数用 Counter:
from collections import Counter
counts = Counter(words)分组用 defaultdict:
from collections import defaultdict
groups = defaultdict(list)
for k, v in pairs:
groups[k].append(v)队列操作用 deque:
from collections import deque
queue = deque()
queue.append(1)
queue.append(2)
queue.popleft()适合的场景
常见的数据结构模式可以直接对应到 collections:
Counter→ countingdefaultdict→ grouping / accumulationdeque→ efficient queues
这样写更短,也让常见操作的意图更明确。
Priority Queues with heapq
需要不断维护排序时,反复对 list 排序会很慢。
例如每次加入元素后排序:
data.append(x)
data.sort()或反复取最小值:
min_value = min(data)数据量大时,这些操作会越来越贵。
用 heapq 维护堆
heapq 实现了 binary heap。
import heapq
heap = []
heapq.heappush(heap, 5)
heapq.heappush(heap, 1)
heapq.heappush(heap, 3)
smallest = heapq.heappop(heap)堆会把最小元素放在索引 0。
适合的场景
需要反复取集合里的最小值(或最大值)时,用 heapq 维护 priority queue,不用每次重新排序。