第2章 类以下层级的语法最佳实践
按原书第2章 Syntax Best Practices—Below the Class Level重建:列表推导与生成器表达式、迭代器与生成器、协程、装饰器、with与contextlib。
先做预测
先预测:一个示例在作者机器上运行成功,是否足以证明它可维护?不能。还要明确解释器与依赖、输入边界、失败路径、可观察结果和重建步骤。给出本章的第一个契约,把它放进可重复流程。
原书骨架与现代迁移
官方章节围绕列表推导与生成器表达式、迭代器与生成器、协程、装饰器、with与contextlib展开。原书出版于Python 2.5与早期敏捷工具生态,本章保留它解释“为什么”的结构;命令和安全默认按当前Python、标准库与PyPA维护文档迁移,不把EasyInstall、distutils安装命令、旧CI或旧项目平台直接当成新项目默认。
承接前两项,把局部语法或工具放回应用数据流。阅读时沿输入、协议、状态、输出和证据追踪,避免只背API名称。
def windows(values, size):
iterator = iter(values)
window = []
for value in iterator:
window.append(value)
if len(window) == size:
yield tuple(window)
window.pop(0)机制一:责任与数据流
推导式适合单一、可读的映射或过滤,生成器表达式把结果惰性传给消费者;当副作用、分支或异常复杂时应改回显式循环。 迭代协议由iter与next协作,生成器保存暂停点与局部状态;惰性只降低同时驻留的元素,不会自动限制上游无限生产。 先写出公共行为和失败类型,再选择语法或工具。这样即使实现从原书工具迁到当前生态,调用者仍能依据相同契约判断结果。
提醒我们:抽象不能消除成本,只会改变成本出现的位置。包装、生成器、构建系统、CI或缓存都必须说明资源、顺序和异常传播。
from functools import wraps
def traced(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"call={func.__name__}")
return func(*args, **kwargs)
return wrapper机制二:失败与边界
原书基于生成器send讨论协程,把数据推入暂停的执行体;现代async协程语法不同,但消息输入、取消、关闭和异常传播仍是同一类协议问题。 装饰器在定义阶段替换可调用对象,适合横切契约;包装器要保留元数据、参数与异常语义,不能把业务控制流藏进不可见全局状态。 边界实验至少包含正常、空输入、上限附近、依赖失败和重复执行。涉及网络、并发或外部制品时,再加入超时、取消、部分完成与摘要校验。
历史工具不等于无价值。正确迁移是先提取声明式配置、隔离、持续反馈和可回滚发布等不变量,再用维护中的接口重写;错误做法是机械替换命令却保留隐式环境和不可追踪副作用。
from contextlib import contextmanager
@contextmanager
def opened(path):
handle = open(path, encoding="utf-8")
try:
yield handle
finally:
handle.close()机制三:证据闭环
负责收束验收。上下文管理器把获取和释放绑成词法作用域,即使异常也执行清理;它适合文件、锁、事务和临时资源,但退出方法必须明确是否吞掉异常。 保存解释器、依赖锁定、输入、命令、退出状态、关键输出和制品摘要,才能让另一台干净机器重放同一结论。
实战验收清单
- 在隔离环境运行三段示例,记录解释器实现、版本和依赖来源。
- 为核心行为增加正常、空输入、失败和重复执行测试,先看到失败再修改实现。
- 清理缓存和临时文件后重跑,证明结果不依赖工作区残留。
- 对历史命令写出当前替代路径,并说明保留的架构不变量与不再采用的安全默认。
迁移决策题
设想团队正在维护一个已经运行多年的Python服务:它仍依赖本章对应的历史工具,但业务不能停机。先不要直接重写。第一步列出列表推导与生成器表达式承担的真实输入和输出,再用迭代器与生成器识别构建或运行时依赖;第二步把协程放进隔离实验,证明当前行为与失败类型;第三步用装饰器设计兼容层,让旧入口和新入口在同一组契约测试下运行;最后以with与contextlib保存制品摘要、性能或行为差异与回滚条件。只有新路径在正常、边界和故障输入上都达到既定条件,才逐步切换流量或调用者。这样迁移的是可验证契约,而不是把一个旧命令盲目替换为一个新命令。
常见误区
本章回顾
本章逐项覆盖列表推导与生成器表达式、迭代器与生成器、协程、装饰器、with与contextlib。方法是用可读接口表达责任,用边界测试证明失败语义,再以可重建环境和制品证据完成闭环。