Skip to content

22|JSON 数据

JSON(JavaScript Object Notation)是最常用的数据交换格式。配置文件、API 响应、数据存储——这些场景都大量使用 JSON。Python 标准库的 json 模块提供了完整的 JSON 解析和生成功能。

一、JSON 与 Python 类型的对应

JSONPython
objectdict
arraylist
stringstr
numberint / float
true / falseTrue / False
nullNone

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"])   # True

json.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 每行一个对象,适合大文件。