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

Python 从入门到初级(11):CSV 与 JSON:生成第一份订单报表

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

很多办公数据不是数据库,而是从系统导出的 CSV。Python 可以读取这些记录、按条件计算,再输出其他程序也能读取的 JSON。本篇完成第一份订单统计报表。

CSV 订单经过筛选和分组,生成 JSON 报告

1. 先看数据,再决定统计规则

在示例目录的 data/orders.csv 保存:

order_id,category,amount_cents,status
A001,图书,5900,paid
A002,办公,12500,paid
A003,图书,3900,pending
A004,数码,19900,paid
A005,办公,4500,cancelled

每行一笔订单,金额单位是整数分。统计规则是:保留全部订单数量,但只有 status 为 paid 的订单计入已支付数量和金额;pending、cancelled 不计入已支付汇总。

正确基准是总订单 5 笔,已支付 3 笔,金额 38300 分,即 383.00 元。分类中图书 5900 分、办公 12500 分、数码 19900 分。先写下这个人工核对值,后面才能判断代码是否正确。

2. CSV 和 JSON 各适合什么

CSV 适合规则的二维表格,通常有表头和多条记录;JSON 能表达字典、列表和嵌套结构,常用于接口与结构化报告。

CSV 字段里可以有带引号的逗号、换行等内容,所以使用 csv 模块读取,不要拿字符串 split 代替解析器。JSON 则需要用 json.loads 或 json.load 解析,不要把文本当 Python 代码执行。

相关格式处理见 csv 文档 和 json 文档。

3. 完整示例:从 CSV 生成报告

把数据文件放在正确位置,运行 python lesson11.py:

import csv
import json
from pathlib import Path

BASE = Path(__file__).resolve().parent
with (BASE / "data" / "orders.csv").open(newline="", encoding="utf-8-sig") as handle:
    orders = list(csv.DictReader(handle))

paid_count = 0
paid_amount = 0
by_category = {}
for order in orders:
    amount = int(order["amount_cents"])
    if order["status"] != "paid":
        continue
    paid_count += 1
    paid_amount += amount
    category = order["category"]
    by_category[category] = by_category.get(category, 0) + amount

summary = {
    "total_orders": len(orders),
    "paid_orders": paid_count,
    "paid_amount_cents": paid_amount,
    "by_category_cents": by_category,
}
output = BASE / "output" / "lesson11.json"
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text(json.dumps(summary, ensure_ascii=False, indent=2), encoding="utf-8")
print(json.dumps(summary, ensure_ascii=False, indent=2))
print("结果文件:", output)

DictReader 把每行读成以表头为键的字典。刚读到的 amount_cents 仍是字符串,参与计算前必须转换成 int。

by_category.get(category, 0) 的作用是:第一次遇到某个分类,从 0 开始;后面再遇到它,就继续累加。这个模式也能用于员工工时、文件类型和日志级别统计。

4. 为什么打开文件时这样写

newline="" 让 csv 模块按自身规则处理换行。utf-8-sig 可兼容 UTF-8 文件开头的 BOM,常见于部分表格软件导出的文件;它不是自动识别所有编码的工具。

CSV 文件较大时可以边读取边统计。本例为了观察原始记录先生成列表,因此会把全部记录放进内存。后续处理大文件时应重新评估这个选择。

ensure_ascii=False 让输出 JSON 保留中文展示,indent=2 便于人阅读。这两项不是金额计算规则,也不会改变 paid 的筛选条件。

5. 核对文件,而不只看终端

程序会在 output/lesson11.json 中保存结果。打开它,检查 total_orders=5、paid_orders=3、paid_amount_cents=38300,再逐类对照金额。

这里 write_text 会覆盖同一个教学报告,重复运行仍更新这份文件。第 18 篇会改为让用户指定新输出文件,并拒绝覆盖已有结果。

还可以把 A003 改为 paid:预期已支付变为 4 笔、42200 分,图书分类变为 9800 分。改完练习后恢复原始数据,便于后续章节使用同一基准。

6. 这份简单脚本的边界

它假定数据符合表头和字段约定。缺列、金额不是整数或订单重复时,目前可能报错或统计出不符合业务预期的结果。

不要把“能处理示例 CSV”误认为“能接受任何外部文件”。第 13 篇会把读取和统计拆成模块,并补充表头、重复编号、状态及金额验证。

练习:额外统计 pending 的数量,但不要把它加入已支付金额。参考结果应为 1 笔。先明确“总数、状态数量、金额”分别代表什么,再添加统计字段。


上一篇:文件与 pathlib:读写文本、编码和路径 · 系列目录 · 下一篇:时间、正则与 Counter:统计日志和异常


评论