Python 工程复杂度的控制策略

1次阅读

模块拆分应避免过早创建utils目录,需待业务逻辑稳定后再提取无状态、跨域通用代码并严格约束;可选依赖须按场景分组、加版本约束,禁用无版本声明。

Python 工程复杂度的控制策略

模块拆分时,别过早抽象出 utils 目录

很多团队一上手就建 utils,结果半年后里面塞了 83 个函数,彼此依赖混乱,改一个 format_timestamp 能让测试挂掉三个服务。这不是复用,是债务打包。

实操建议:

立即学习Python免费学习笔记(深入)”;

  • 先让功能在业务模块里“长出来”——比如 order_processing.py 里反复出现的校验逻辑,再考虑抽成 order_validation.py
  • utils 只收真正无状态、无业务语义、跨域通用的代码(如 parse_iso_datetime),且必须带类型注解和单测
  • 一旦某个 utils 函数被两个以上不相关的业务模块导入,立刻检查它是否隐含了未声明的上下文依赖(比如悄悄读了 os.environ

pyproject.toml 里别满可选依赖

看到别人写 dev = ["pytest", "black", "mypy", "pre-commit", ...] 就照抄,结果 CI 构建时 pip 解析依赖图耗时翻倍,本地 poetry install 卡住还查不出原因。

实操建议:

立即学习Python免费学习笔记(深入)”;

  • 按场景分组:只把真正在开发期用的放 dev;CI 专用工具(如 coveralls)单独设 ci 组;文档生成类(sphinx)归 docs
  • 所有可选依赖必须加版本约束,禁止 "black" 这种写法,用 "black>=24.0.0,
  • CI 脚本里显式指定安装组:pip install ".[ci]",避免 pip 自动合并多个组引发冲突

类型提示不是装饰,是接口契约

加了 def process(data: dict) -> List: 等于没加——dictList 不提供任何校验或 IDE 支持,运行时照样传错结构崩掉。

实操建议:

立即学习Python免费学习笔记(深入)”;

  • TypedDict 或 Pydantic v2 的 BaseModel 描述数据形状,哪怕只是临时验证;dataclass 更适合内部状态封装
  • 函数参数/返回值类型必须精确到具体字段级约束(如 Optional[str] 而非 Any),否则 mypy 会绕过检查
  • 类型检查要跑在 CI 里,但别用 mypy --strict 一步到位——先从 --disallow-untyped-defs--disallow-incomplete-defs 开始,逐步收紧

测试不是覆盖率数字,是隔离边界的探测器

追求 90%+ 覆盖率后发现,test_order_creation 里 mock 了数据库、HTTP 客户端、时间模块,最后这个测试既慢又脆,重构一次就得重写三处 patch。

实操建议:

立即学习Python免费学习笔记(深入)”;

  • 单元测试只打穿一层:函数输入 → 函数输出,其他依赖全用真实轻量对象(如内存字典代替 DB,httpx.MockTransport 代替 requests-mock)
  • 集成测试才该启动真实依赖,但必须限定范围——比如只测 OrderService + 内存 SQLite,不拉起 Redis 或外部 API
  • 每个测试文件开头加注释说明它验证的边界:# 验证订单金额计算在税费变更时仍正确,而不是 # 测试 order module

复杂度真正的麻烦不在代码行数,而在你改一行时,得翻几个文件、问几个人、猜三次意图。控制不住这点,再多的架构图和规范都只是延缓爆炸的时间。

text=ZqhQzanResources