Python 专区
Python 项目组织与工程规范
把脚本整理成可安装、可测试、可交接的命令行项目。
展开本篇目录
一、为什么要把脚本整理成项目?
一个脚本在你电脑上运行,并不代表同伴能找到入口、安装依赖或理解输出。项目组织的目标是让输入、处理逻辑、配置、结果和验证方式都有明确位置。
本篇先修知识为 Python 函数、模块与基本终端操作。学完应能将一个小型成绩统计程序拆成包,通过命令行运行,并由测试验证核心逻辑。项目越小,结构越应克制,不需要一开始就引入复杂框架。
二、先区分解释器、包、模块和工作目录
| 名称 | 含义 | 例子 |
|---|---|---|
| 解释器 | 真正执行代码的 Python | .venv/bin/python |
| 模块 | 可导入的 Python 文件 | stats.py |
| 包 | 组织模块的命名空间 | scorelab |
| 工作目录 | 相对路径解析的起点 | 终端当前目录 |
| 项目根目录 | 配置、源码和文档所在目录 | pyproject.toml 所在处 |
python -m pip 让 pip 与当前解释器配套。不要在项目中命名 json.py、sqlite3.py 等文件,否则可能遮蔽标准库。
|
Windows PowerShell:.venv\Scripts\Activate.ps1;macOS/Linux:source .venv/bin/activate。如果不想激活,也可直接调用虚拟环境内的 Python。
三、从最小可维护结构开始
|
src 布局将源码与项目根目录隔开,有助于避免“在根目录碰巧能导入,安装后却失败”。它需要安装项目,而不是到处追加 sys.path。小型一次性脚本也可以使用平铺结构,关键是统一入口和导入方式。
四、pyproject.toml:记录项目事实
|
项目分发名 arclab-scorelab 与导入名 scorelab 可以不同。build-system 声明构建工具;dependencies 声明运行依赖;开发工具依赖应另外管理。这个练习不需要上传到 PyPI。
在根目录运行 python -m pip install -e .,可编辑安装会让源码修改在环境中生效。安装可能需要联网获取构建工具,但实际示例运行只用标准库。
五、核心函数:与终端和文件操作分离
src/scorelab/stats.py:
|
函数接受数值列表,返回一个数,不直接读取 CSV、不打印日志,也不退出进程,因此容易单独测试。类型注解帮助读者和检查工具理解约定,不会自动执行运行时类型校验;上例假设调用方已经把输入转换为数值。
六、命令行入口与可预期的错误
src/scorelab/cli.py:
|
src/scorelab/__main__.py:
|
src/scorelab/__init__.py 可以暂时为空。
|
两条命令都输出 85.00。python -m scorelab 120 会打印错误并以非零状态退出。不要捕获全部异常后仍打印“成功”,这会让自动化脚本把失败当成成功。
七、路径、配置与日志
7.1 路径由入口决定
|
相对路径依赖当前工作目录。更通用的入口是 --input 和 --output,由用户明确提供;创建输出目录时使用 mkdir(parents=True, exist_ok=True)。不要为方便而在函数内部全局 chdir。
7.2 配置和密钥分开
普通配置可放 TOML/JSON 或命令行参数。Token 不写进源码、Notebook 输出或截图;从环境变量读取,并提交不含真实值的 .env.example。仅把文件加入 .gitignore 不能删除已经提交进历史的秘密。
7.3 日志保留运行上下文
|
记录输入路径、数量、规则和错误,不输出个人敏感数据或密钥。核心库代码使用自己的 logger,通常由命令行入口配置全局日志。
八、测试:让规则成为可执行的说明
tests/test_stats.py:
|
|
覆盖正常、零分、空列表和非法值。测试要表达业务约定,而不只是重复实现中的每一行代码。涉及临时文件时使用临时目录,不要让测试修改真实数据。
九、格式、静态检查与依赖复现
| 检查 | 解决什么问题 | 不能替代什么 |
|---|---|---|
| 格式化 | 缩进、空格和换行统一 | 业务正确性 |
| lint | 未用变量、部分易错写法 | 完整运行验证 |
| 类型检查 | 接口类型不匹配 | 输入是否合法 |
| 单元测试 | 已定义规则是否满足 | 所有真实场景 |
| 集成测试 | 模块连接后是否正常 | 人工观察和业务确认 |
可进一步使用 Ruff 等工具,但先理解每条提示。不要为了“让检查变绿”直接关闭所有规则。
pip freeze > requirements.txt 是当前环境的版本快照,可能包含无关包;在干净环境生成更有意义。pyproject.toml 中的依赖范围不等于完全锁定的环境,还要记录 Python 版本、平台和实际验证命令。不要提交 .venv/。
建议 .gitignore:
|
十、README 与交付
README 至少说明:项目做什么、需要什么版本、怎样安装、怎样运行、示例输入输出、怎样测试、已知限制。命令应能从一个明确目录完整执行,不能依赖作者记忆中的本机路径。
下载完整项目 ZIP,解压进入目录后执行:
|
预期:均分为 85.00,三个测试方法通过。再执行 python -m scorelab 120,预期失败并提示范围错误;失败也是接口的一部分。
十一、常见问题
| 问题 | 优先检查 |
|---|---|
| ModuleNotFoundError | 是否用当前解释器安装了项目,包名是否正确 |
| pip 装了但不能导入 | python -m pip --version 与解释器路径是否一致 |
| 换目录就读不到文件 | 是否使用未说明的相对路径 |
| 测试依赖执行顺序 | 是否共享可变全局状态或遗留文件 |
| 同伴结果不同 | Python/依赖版本、输入数据、随机种子是否记录 |
十二、练习与完成标准
- 增加最高分函数及空输入测试,不要改变 average 的规则。
- 给入口增加
--precision,限制为 0~4 位小数,并测试非法值。 - 增加从 CSV 读取的入口;明确哪些行拒绝、哪些行忽略,保留行数报告。
- 找同伴在新环境按 README 跑通,记录其遇到的第一个问题并修正文档。
验收: 安装与入口统一,核心逻辑能独立测试,错误返回非零状态,版本和路径可说明,仓库没有密钥和虚拟环境。
十三、学习资料
- Python Packaging 官方项目教程:理解 pyproject 与构建。
- Python argparse:命令行参数。
- Python unittest:测试组织与断言。
- Python logging:日志记录。