Administrator
Administrator
发布于 2026-10-31 / 0 阅读
0
0

Python 从入门到初级(20):综合项目:交付一个可测试的订单报表工具

本篇是《Python 从入门到初级》第 20 / 20 篇。示例使用 Python 3.12 兼容语法,完整目录结构与数据见配套源码包。

最后一篇把前面学到的文件、CSV/JSON、函数、模块、异常、命令行和测试组合起来,交付一个别人解压后也能使用的订单报表项目。

明确需求、验证工具、组织文件,最后打包并在新位置复验

1. 先写项目交付标准

项目接收一份订单 CSV,验证字段,统计全部订单数、已支付数量和分类金额,输出 JSON。输入金额单位固定为非负整数分,状态固定为 paid、pending、cancelled。

使用者可以查看帮助、预览结果,选择新输出文件;错误时有原因和非零退出码;已有报告不被静默覆盖;测试可以重复运行。

它不承担付款对账、退款、税费或币种换算,也没有并发写入和大规模流式处理。本项目交付的就是这一组明确能力。

2. 目录中分别放什么

order-report/
├── report_cli.py
├── ops_tools/
│   ├── __init__.py
│   └── orders.py
├── data/orders.csv
├── tests/test_orders.py
└── README-project.md

report_cli.py 作为入口,orders.py 实现读取、验证、汇总和输出,data 放教学样本,tests 保存验收预期。完整文件都在源码包中,分别来自第 13、18、19 篇。

这次不再重新复制一套统计逻辑,而是保持已有模块的复用关系。改规则时只需要修改相应职责的位置,再运行测试验证影响。

3. README 要让第一次看到项目的人也能运行

项目附带的 README 内容如下:

# 订单报表工具

需求:读取包含 order_id、category、amount_cents、status 的 CSV,统计全部订单数、已支付订单数、已支付整数分金额及分类金额,输出 UTF-8 JSON。

环境:Python 3.12 或兼容版本,只使用标准库。进入本项目根目录后,使用对应环境的 python 运行。

```text
python -m unittest discover -s tests -v
python report_cli.py --output output/report.json --dry-run
python report_cli.py --output output/report.json
```

示例数据共 5 单,其中 paid 3 单、38300 分。输出文件存在时拒绝覆盖,请选择新文件名。

退出码:成功为 0,文件或业务数据处理失败为 1,命令参数错误为 2。日志写入标准错误,统计 JSON 写入标准输出。

输入规范:金额为非负整数分;订单编号不重复;分类非空;状态为 paid、pending、cancelled 之一。空表允许,但必须保留表头。数据均为教学样本。

不在范围:付款对账、退款、税费、币种换算、海量数据流式处理、并发写入和生产权限管理。

除了启动命令,还写明环境、字段、金额单位、正常基准、退出码和不覆盖规则。一个只写“运行 main.py”的说明,往往省略了接手者最需要的信息。

4. 按验收顺序运行

在项目根目录依次执行:

python -m unittest discover -s tests -v
python report_cli.py --help
python report_cli.py --output output/report.json --dry-run
python report_cli.py --output output/report.json

如果使用完整学习源码目录,会运行 18 项测试;交付的订单子项目只带订单测试,因此是 13 项。干净项目中的报告基准是 5 单、3 笔 paid、38300 分。

再原样生成一次,确认工具拒绝覆盖;换一个新文件名,确认可正常生成。对缺文件和重复编号也各做一次检查,确保失败路径可解释。

5. 用标准库生成一个内容明确的压缩包

在完整学习源码根目录运行 bundle_project.py。它只打包列出的项目文件,不递归收集虚拟环境、缓存或个人配置。

from pathlib import Path
from zipfile import ZIP_DEFLATED, ZipFile

BASE = Path(__file__).resolve().parent
FILES = ["report_cli.py", "ops_tools/__init__.py", "ops_tools/orders.py",
         "data/orders.csv", "tests/test_orders.py", "README-project.md"]


def main():
    output = BASE / "output" / "order-report-project.zip"
    output.parent.mkdir(exist_ok=True)
    for name in FILES:
        if not (BASE / name).is_file():
            raise FileNotFoundError(name)
    with ZipFile(output, "x", compression=ZIP_DEFLATED) as archive:
        for name in FILES:
            archive.write(BASE / name, "order-report/" + name)
    print("项目包:", output)


if __name__ == "__main__":
    main()

预期生成 output/order-report-project.zip。使用 x 模式意味着同名包已存在时拒绝覆盖,重复练习时可以使用新的输出名称。ZIP 操作机制见 zipfile 文档。

这只是代码交付,不是把 Python 解释器也打进去的独立可执行程序。接手者仍需要匹配的 Python 环境。

6. 在新位置复验,才能发现路径依赖

把包解压到另一个独立目录,进入 order-report,再执行 README 里的测试、预览和生成命令。路径、包结构和样本文件都正确时,结果应保持一致。

如果只在原来的电脑和目录能运行,检查是否遗漏文件、依赖了当前目录、误用了全局安装的包或把绝对路径写进代码。这个练习比只检查“压缩包存在”更接近交付要求。

7. 学完后可以独立尝试什么

用相同结构做文件清单导出、值班记录统计、商品价格对比或内部接口数据同步。先定义输入输出,再拆函数与模块,最后补上边界验证、日志和测试。

如果想继续向运维发展,可以把 HTTP 客户端与退出码接入调度或流水线;向数据方向可以学习更大规模的数据处理库;向 Web 方向可以再学框架和服务部署。

不必把所有方向同时学完。能够把一个具体需求变成可运行、可解释、可验证、别人也能接手的小工具,就是这套从入门到初级教程的实际目标。


上一篇:自动化测试:保护报表与文件整理规则 · 系列目录 · 本篇为系列收尾


评论