用途:这是一份 Python 惯用法规范,把架构层面的原则落成具体可执行的 Python 写法,只讲 Python 的“怎么做”,不重复与语言无关的原则,也不负责 lint/类型检查器配置。
主要能力:
- 错误即值:预期失败(领域、解析、鉴权、持久化)应进入返回类型,如 Result[ActiveUser, UserLookupError],而非抛异常;抛异常只用于缺陷。边界处(StopIteration、KeyError、ORM 完整性错误)捕获并翻译为领域值/错误。
- 解析而非校验:在边界把不可信输入一次性转成领域类型并保留精化类型,数据库行与配置也要解析回领域类型。解析器命名 parse_x,智能构造器 make_x/create_x,谓词 is_x;返回精化值的不要叫 validate_x。
- 让非法状态不可表示:用标签联合(Union of frozen dataclass + Literal 标签)建模生命周期状态,用 Literal/StrEnum 表示封闭集合,match 穷尽匹配并在兜底放 assert_never,使新增变体变成类型错误。避免布尔行为标志参数。
- 值对象与实体:@dataclass(frozen=True, slots=True) 提供值相等与不可变;实体有身份,用 isinstance 守卫的 eq 基于稳定 id,hash 默认保留,除非确需集合成员资格。
- 端口用 Protocol 而非 ABC:typing.Protocol 是默认端口,单方法依赖可直接用 Callable,多方法才用 Protocol/ABC。
- 持久化无知:领域类不继承 ORM 基类,用 SQLAlchemy 命令式映射让 ORM 导入模型;聚合按 id 关联而非内嵌;注意惰性加载导致的 SELECT N+1。
- 依赖注入与启动:优先显式注入而非 mock.patch,单一组合根 bootstrap() 装配真实适配器,测试在此替换假实现;用闭包或 functools.partial 组合处理器。
- 资源与事务边界:with 块承载事务/资源作用域,默认回滚,只有全部成功并显式 commit() 才提交。
- Any/cast/type-ignore 纪律:不用裸 Any,用 object + 收窄;cast() 是最后手段并需 # SAFETY: 注释;优先 # pyright: ignore[reportX];穷尽匹配用 assert_never,善用 Self、@override、@final。
使用方式:先读仓库,若已有错误、schema、类型检查、模块布局、测试约定则沿用,不引入竞争方案;绿地项目才套用默认值。规则冲突时优先级为:正确性/安全 > 现有项目约定 > 改进局部设计 > 避免大迁移 > 记录权衡。新代码路径遵循本标准,不为无关改动强制全项目迁移。
适用场景:新代码、绿地项目,或仓库尚无相关约定的 Python 项目;3.10 以下或仓库尚未采用现代写法时,退回手写默认方案。
限制:不负责 lint/类型检查器配置、测试策略与覆盖率、结构化日志等,这些由其他技能负责;品牌化 NewType 只在确实易混淆处使用,否则是多余包装。具体参考文件(errors.md、parsing.md、modeling.md、ports-persistence.md、conventions.md)内容暂未提供。