以文本形式表示的嵌套数据
JSON 是配置文件以及程序与 Web API 之间传输数据的常用格式。它由对象 {"key": value}、数组 [1, 2]、字符串、数字、true/false 和 null 构成,与 Python 直接对应:对象变成字典,数组变成列表,true/false 变成 True/False,null 变成 None。与 CSV 表格不同,JSON 可以嵌套:一个订单可以包含成交列表,每个成交有自己的字段。
import json
# Text to Python: loads() ("load string")
text = '{"symbol": "AAPL", "fills": [{"price": 184.25, "qty": 100}], "open": true, "note": null}'
order = json.loads(text)
print(order["fills"][0]["price"]) # 184.25
print(order["open"], order["note"]) # True None
# Python to text: dumps() ("dump string")
print(json.dumps({"symbol": "AAPL", "qty": 200})) # {"symbol": "AAPL", "qty": 200}文件:load 与 dump
不带 s 的版本用于文件:json.load(file) 读取并解析已打开的文件,json.dump(data, file) 写入文件。传入 indent=2 让文件便于人阅读,传入 sort_keys=True 让键的顺序稳定,这样版本控制中的差异更小。始终用 with 和 encoding="utf-8" 打开文件。
import json
# Save a config, then load it back
config = {"fee": 0.001, "symbols": ["MSFT", "AAPL"], "limits": {"max_qty": 500}}
with open("config.json", "w", encoding="utf-8") as file:
json.dump(config, file, indent=2, sort_keys=True)
with open("config.json", encoding="utf-8") as file:
print(file.read())
# {
# "fee": 0.001,
# "limits": {
# "max_qty": 500
# },
# "symbols": [
# "MSFT",
# "AAPL"
# ]
# }
with open("config.json", encoding="utf-8") as file:
print(json.load(file) == config) # True往返之后会丢失的东西
JSON 的类型很少,所以一些 Python 值在途中会发生变化。元组读回来是列表,字典的键读回来一律是字符串({1: "a"} 变成 {"1": "a"}),集合、日期和自定义对象在转换前根本无法导出(TypeError),例如日期用 .isoformat()、集合用 sorted(...) 转换。另外,NaN 和无穷大不是合法的 JSON。
import json
from datetime import date
# Tuples become lists, int keys become strings
data = {"pair": (1, 2), 7: "seven"}
print(json.loads(json.dumps(data))) # {'pair': [1, 2], '7': 'seven'}
# A date has to be converted by hand
today = date(2025, 1, 2)
print(json.dumps({"day": today.isoformat()})) # {"day": "2025-01-02"}无效输入
来自外部的文本,比如交易所发来的消息,可能根本不是合法的 JSON。这时 json.loads 会引发 json.JSONDecodeError(ValueError 的一种);而合法的 JSON 也可能缺少你要的键(KeyError)或形状不同(TypeError)。请用 try/except 包住解析过程,并决定坏消息对你的程序意味着什么。下一个主题会完整讲解异常。
import json
# Bad input raises, so catch it where you parse
def get_price(text):
try:
return json.loads(text)["price"]
except (ValueError, KeyError, TypeError):
return None
print(get_price('{"price": 184.25}')) # 184.25
print(get_price("not json")) # None
print(get_price('{"symbol": "AAPL"}')) # Nonejson.dumps 或 json.dump 生成文本,让 json.loads 或 json.load 读取。合并设置时也一样:修改前先复制,避免一份配置影响另一份。json.loads(text)/json.dumps(data)处理字符串;json.load(file)/json.dump(data, file)处理文件。indent=2和sort_keys=True让文件易读且稳定。- 无效输入会引发
ValueError、KeyError或TypeError:只捕获你预期的。
下一节:异常与错误处理,让你的程序清晰地失败,并在该恢复时恢复。
实验:评分内容
- 用
order_total汇总 JSON 文件中的订单25 分 - 用
save_config把设置保存为易读的 JSON25 分 - 用
parse_quote安全地读取报价消息25 分 - 用
merge_configs把设置叠加到默认值上25 分