Appearance
22|JSON 数据
JSON(JavaScript Object Notation)是最常用的数据交换格式。配置文件、API 响应、数据存储——这些场景都大量使用 JSON。Python 标准库的 json 模块提供了完整的 JSON 解析和生成功能。
一、JSON 与 Python 类型的对应
| JSON | Python |
|---|---|
| object | dict |
| array | list |
| string | str |
| number | int / float |
| true / false | True / False |
| null | None |
Python 的 json 模块在这两组类型之间自动转换。datetime 对象、集合、元组等 Python 特有类型不能直接被 JSON 序列化,需要手动处理。
二、解析 JSON 字符串
python
import json
raw = '{"name": "Alice", "age": 25, "active": true}'
data = json.loads(raw)
print(data["name"]) # Alice
print(data["age"]) # 25
print(data["active"]) # Truejson.loads() 把 JSON 字符串解析成 Python 对象。
解析失败:
python
json.loads("{bad json}") # json.JSONDecodeError常见原因:缺少引号、多余的逗号、括号不匹配。排查时先看原始 JSON 内容。
三、生成 JSON 字符串
python
import json
data = {"name": "Alice", "age": 25}
text = json.dumps(data)
print(text) # '{"name": "Alice", "age": 25}'美化输出:
python
json.dumps(data, indent=2, ensure_ascii=False)| 参数 | 作用 |
|---|---|
indent | 缩进空格数,让输出可读 |
ensure_ascii=False | 中文不转义成 \uXXXX |
sort_keys=True | 按键排序,输出稳定 |
python
data = {"name": "张三", "age": 25}
json.dumps(data)
# '{"name": "\\u5f20\\u4e09", "age": 25}'
json.dumps(data, ensure_ascii=False)
# '{"name": "张三", "age": 25}'四、读写 JSON 文件
python
import json
from pathlib import Path
# 写
data = {"users": [{"name": "Alice"}, {"name": "Bob"}]}
Path("data.json").write_text(
json.dumps(data, indent=2, ensure_ascii=False),
encoding="utf-8"
)
# 读
content = Path("data.json").read_text(encoding="utf-8")
data = json.loads(content)或直接用 json.load()/json.dump():
python
# 读
with open("data.json", "r", encoding="utf-8") as f:
data = json.load(f)
# 写
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, indent=2, ensure_ascii=False)json.load() 从文件对象读取并解析,json.dump() 把对象写入文件。带 s 的版本(loads/dumps)操作字符串,不带 s 的版本操作文件对象。
五、处理非标准类型
JSON 不支持 datetime、set、tuple 等类型。序列化时需要自定义处理:
python
from datetime import datetime
import json
now = datetime.now()
# datetime 不能直接序列化
json.dumps({"time": now}) # TypeError
# 自定义编码器
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
return super().default(obj)
json.dumps({"time": now}, cls=CustomEncoder)
# '{"time": "2024-06-01T10:30:00"}'解析时再把字符串转回 datetime:
python
data = json.loads('{"time": "2024-06-01T10:30:00"}')
dt = datetime.fromisoformat(data["time"])六、从 JSON 到 Python 对象
JSON 解析后得到的是字典和列表的嵌套结构。访问深层字段时,中间某层不存在会报 KeyError:
python
data = {"user": {"profile": {"name": "Alice"}}}
data["user"]["profile"]["name"] # Alice
data["user"]["address"]["city"] # KeyError安全访问:
python
# 用 get 逐层降级
data.get("user", {}).get("address", {}).get("city")
# None,不会报错七、JSON Lines 格式
每行一个 JSON 对象,适合流式处理:
python
# 写入
records = [{"name": "Alice"}, {"name": "Bob"}]
with open("data.jsonl", "w", encoding="utf-8") as f:
for record in records:
f.write(json.dumps(record, ensure_ascii=False) + "\n")
# 读取
with open("data.jsonl", "r", encoding="utf-8") as f:
for line in f:
record = json.loads(line.strip())
print(record)JSON Lines(.jsonl)比单个巨大 JSON 数组更易处理——逐行读取,内存占用稳定。
记忆锚点:json.loads() 字符串→Python,json.dumps() Python→字符串;带 s 操作字符串,不带 s 操作文件;ensure_ascii=False 保留中文;indent 美化输出;JSON 不支持 datetime、set、tuple,需要自定义编码器;深层嵌套用 .get() 安全访问;.jsonl 每行一个对象,适合大文件。