Python 包依赖方向的设计原则

2次阅读

依赖声明必须写在 install_requires 或 pyproject.toml 的 [project.dependencies] 中,requirements.txt 仅用于开发环境;运行时依赖与开发依赖须分离,后者应通过 extras_require 或 [project.optional-dependencies] 声明;需避免循环依赖、平台不兼容及环境标记误用,并在干净环境中验证安装。

Python 包依赖方向的设计原则

依赖声明必须写在 install_requires 里,而不是 requirements.txt

PyPI 安装时只读取 setup.pypyproject.toml 中的 install_requires(或 dependencies),requirements.txt 是开发环境用的,打包发布后完全无效。

  • 用户用 pip install your-package 时,requirements.txt 里的包一个都不会装
  • install_requires 要写最小兼容版本,比如 "requests>=2.25.0",别写死 "requests==2.28.1",否则容易和用户已有依赖冲突
  • 如果用 pyproject.toml,对应字段是 [project.dependencies],不是 [build-system.requires](后者只管构建工具本身)

运行时依赖和开发依赖必须严格分离

测试、格式化、类型检查这些工具,放进 extras_require(或 [project.optional-dependencies]),而不是 install_requires

  • 错误示例:install_requires=["pytest", "black"] → 用户装你的包,结果被强制装了测试框架
  • 正确做法:extras_require={"dev": ["pytest>=7.0", "black>=23.0"]},用户按需执行 pip install your-package[dev]
  • CI 脚本里用 pip install .[dev],本地开发也应保持一致,避免“在我机器上能跑”问题

避免循环依赖,警惕隐式传递依赖

你声明了 A,A 声明了 B,B 又反向依赖你 —— 这类循环不会报错,但会导致安装失败或导入异常,尤其在使用 pip install --no-deps 或私有源时暴露。

  • 检查方法:pip show your-packageRequires 行,再对每个依赖重复执行,看是否绕回自己
  • 常见陷阱:把内部工具包(如 my-utils)同时发布又作为依赖引入,却没控制好版本边界
  • 如果真需要双向协作,优先考虑合并包,或用插件机制(如 entry_points)解耦,而不是硬依赖

windows/macos/linux 行为不一致时,用 platform_system 条件标记

某些包只在特定系统下需要,比如 pywin32 仅 Windows,macos-notifications 仅 macOS,不加条件会导致其他平台安装失败或警告。

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

  • 写法示例:"pywin32; platform_system == 'Windows'"(注意分号后有空格)
  • 不要用 sys.platformos.namesetup.py 里做判断 —— 构建时平台 ≠ 安装时平台
  • PEP 508 标准支持的环境标记有限,platform_systempython_versionimplementation_name 是最常用且安全的几个

依赖关系不是写完就完的事。真正麻烦的是跨 Python 版本、跨构建方式(setuptools vs. hatch vs. pdm)、跨安装上下文(user install / venv / system)时,同一个 install_requires 字符串可能触发完全不同行为。每次发版前,在干净虚拟环境中试装一次,比读十遍文档都管用。

text=ZqhQzanResources