Python 文件与 JSON 图解:外部数据怎样进入代码
用三条订单看懂 JSON 文件如何解析成 Python 列表与字典、Python 对象如何写回文件,以及 load、loads、dump、dumps 的输入输出区别。
本文目录 8 节 · 点击展开
前面的订单大多直接写在代码里。真实脚本里的数据却常常先存在硬盘文件、接口响应或配置文本中。Python 不能隔着文件直接操作订单字段,必须先跨过一道边界:把外部文本读取并解析成列表、字典等 Python 对象。
处理完成后,方向反过来:Python 对象先变成 JSON 文本,再写回硬盘。这章要看清的就是这两个方向,以及每一步的数据形态。
orders.json 还在 Python 外部
先在脚本旁边创建 orders.json,内容使用本系列固定的三条订单:
[
{"order_no": "A001", "sku": "K161", "amount": 129.0, "status": "已支付"},
{"order_no": "A002", "sku": "K162", "amount": 88.0, "status": "已退款"},
{"order_no": "A003", "sku": "K161", "amount": 199.0, "status": "已支付"}
]
文件看起来很像 Python 的列表和字典,但此时它仍然只是硬盘上的 UTF-8 文本。下面的代码才会打开文件并解析:
import json
with open("orders.json", "r", encoding="utf-8") as file:
orders = json.load(file)
print(type(orders))
print(type(orders[0]))
print(orders[0]["status"])
输出:
<class 'list'>
<class 'dict'>
已支付
orders.json 文本经过 json.load() 后,才成为可访问字段的 list[dict]- 外部输入 · 01硬盘文件
orders.json形态:UTF-8 JSON 文本 - 打开 · 02取得文件对象
open(…, “r”)方向:读取 - 当前操作 · 03读取并解析 JSON
json.load(file)文本语法转换为 Python 类型 - 之后 · 04内存中的对象
orders · list[dict]可以读取 orders[0][“status”]
with 会在代码离开缩进区域时关闭文件;不需要自己记住何时调用 close()。encoding="utf-8" 明确告诉 Python 怎样解释中文字符,避免依赖不同电脑的默认编码。
打开文件时,只先记住三个模式
open() 的第二个参数决定方向:
| 模式 | 方向 | 文件已存在时 | 适合场景 |
|---|---|---|---|
"r" | 读取 | 保留原内容 | 读取订单、配置和文本 |
"w" | 写入 | 清空后重写 | 生成一份完整结果文件 |
"a" | 追加 | 保留原内容,在末尾增加 | 追加简单记录 |
读取普通文本时,file.read() 返回字符串:
with open("order_no.txt", "r", encoding="utf-8") as file:
content = file.read()
print(type(content))
JSON 文件的区别是多一步“按 JSON 语法解析”。因此不要混淆:
file.read():得到原始字符串。json.load(file):从文件对象读取 JSON,并得到 Python 对象。
写入时尤其要确认 "w" 会覆盖原内容。如果目标文件需要保留历史,先判断是否应该换文件名、备份,或明确使用追加模式。
Python 对象怎样写回 JSON 文件
假设前面的处理已经得到固定结果:已支付订单是 A001、A003,共 2 单,总金额 328.0。先用 Python 字典保存汇总:
summary = {
"paid_order_nos": ["A001", "A003"],
"paid_count": 2,
"paid_amount": 328.0,
}
接着使用 json.dump() 写入 paid_orders_summary.json:
import json
summary = {
"paid_order_nos": ["A001", "A003"],
"paid_count": 2,
"paid_amount": 328.0,
}
with open("paid_orders_summary.json", "w", encoding="utf-8") as file:
json.dump(summary, file, ensure_ascii=False, indent=2)
json.dump(),成为硬盘上的 JSON 文件- 内部输入 · 01Python 对象
summary · dict含列表、整数和浮点数 - 打开 · 02取得目标文件对象
open(…, “w”)方向:覆盖写入 - 当前操作 · 03序列化并写入
json.dump(summary, file)ensure_ascii=False 保留中文 - 外部输出 · 04结果文件
paid_orders_summary.json可以交给下一步程序
生成的文件内容是:
{
"paid_order_nos": [
"A001",
"A003"
],
"paid_count": 2,
"paid_amount": 328.0
}
ensure_ascii=False 让中文直接写入;indent=2 只负责排版,让文件更易读,不改变数据含义。
load / loads / dump / dumps 按输入形态区分
四个名字只差一个 s,死记很容易混。先判断数据现在是在文件对象里,还是已经是一段字符串;再判断方向是进入 Python,还是离开 Python。
json.load(file)输入 JSON 文件对象
输出 list / dict 等对象
文件 → Pythonjson.loads(text)输入 JSON 字符串
输出 list / dict 等对象
string → Pythonjson.dump(data, file)输入 Python 对象 + 文件对象
结果 JSON 写入文件
Python → 文件json.dumps(data)输入 Python 对象
输出 JSON 字符串
Python → string四种形式的最小代码如下:
import json
# 文件 → Python 对象
with open("orders.json", "r", encoding="utf-8") as file:
from_file = json.load(file)
# JSON 字符串 → Python 对象
text = '{"order_no": "A001", "status": "已支付"}'
from_text = json.loads(text)
# Python 对象 → JSON 字符串
json_text = json.dumps(from_text, ensure_ascii=False)
# Python 对象 → JSON 文件
with open("one_order.json", "w", encoding="utf-8") as file:
json.dump(from_text, file, ensure_ascii=False, indent=2)
记忆时不要只念函数名,而要把完整方向一起说出来:loads 是“JSON 字符串进入 Python”,dumps 是“Python 对象变成 JSON 字符串”。
文件和 API 最终可以汇入同一处理函数
文件与 API 的来源不同,但只要进入业务逻辑前都得到同样的 list[dict],后面的函数就不需要知道数据来自哪里。
文件路线由 json.load(file) 得到对象。很多 API 客户端则提供类似 response.json() 的动作,直接给出已经解析好的列表或字典;如果接口工具只给原始 JSON 字符串,才需要先调用 json.loads()。
orders.jsonjson.load(file)responseAPI 客户端已解析summarize_paid_orders(orders)下面的处理函数可以直接接收任一路线得到的 orders:
import json
def summarize_paid_orders(orders):
paid_orders = [
order for order in orders
if order["status"] == "已支付"
]
return {
"paid_order_nos": [order["order_no"] for order in paid_orders],
"paid_count": len(paid_orders),
"paid_amount": sum(order["amount"] for order in paid_orders),
}
with open("orders.json", "r", encoding="utf-8") as file:
file_orders = json.load(file)
# 模拟 API 客户端已经解析完成的返回值
api_orders = [
{"order_no": "A001", "sku": "K161", "amount": 129.0, "status": "已支付"},
{"order_no": "A002", "sku": "K162", "amount": 88.0, "status": "已退款"},
{"order_no": "A003", "sku": "K161", "amount": 199.0, "status": "已支付"},
]
print(summarize_paid_orders(file_orders))
print(summarize_paid_orders(api_orders))
两次结果相同。真正实现网络请求时可以更换 API 工具,但 summarize_paid_orders() 不需要跟着改;它只依赖输入形状,不依赖来源。
用 pathlib 让路径意图更清楚
相对路径取决于脚本运行时的当前目录,不一定等于脚本文件所在目录。先用 Path.cwd() 看当前目录:
from pathlib import Path
print(Path.cwd())
构造 data/orders.json 时,可以让目录和文件名分开表达:
import json
from pathlib import Path
file_path = Path("data") / "orders.json"
with file_path.open("r", encoding="utf-8") as file:
orders = json.load(file)
print(len(orders))
pathlib 属于 Python 标准库,不需要额外安装。入门阶段先掌握 Path.cwd()、Path(...) / "name" 和 Path.open() 就足够了。
文件边界可能失败,但处理方式留到下一篇
这条数据管道只有输入满足边界条件时才能继续:
失败可能发生在“打开”“解码”或“JSON 解析”步骤。先根据报错找到具体停止点,不要用默认值悄悄掩盖问题。
本章不展开 try / except、异常匹配或跳过坏记录。下一篇会把 FileNotFoundError、UnicodeDecodeError、JSONDecodeError 放回各自发生的步骤,并说明脚本应该恢复还是停止。
动手完成一次读取与写回
- 创建本章开头的
orders.json。 - 使用
json.load()读取三条订单。 - 把
orders[0]["status"]打印出来,确认已经得到 Python 对象。 - 调用
summarize_paid_orders(orders),确认数量为2、金额为328.0。 - 使用
json.dump()把汇总写到paid_orders_summary.json。 - 打开结果文件,确认中文没有变成转义字符。
写回步骤可以直接使用:
with open("paid_orders_summary.json", "w", encoding="utf-8") as file:
json.dump(
summarize_paid_orders(orders),
file,
ensure_ascii=False,
indent=2,
)