Menu

Python JSON:用 json 模块读取、写入和解析 JSON

如何在 Python 中读写 JSON:loads、dumps、从文件读取、格式化输出,以及处理真实数据时会遇到的各种特殊情况。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

JSON 和 Python 用的是同样的结构

JSON 是 API、配置文件和 Web 数据交换的默认格式。对 Python 程序员来说幸运的是,JSON 对象直接对应 Python 的字典,JSON 数组对应列表,JSON 字符串对应 str。正因为结构如此接近,在 Python 中读写 JSON 只需要两行代码。

标准库模块 json 负责这两个方向的转换。

解析 JSON 字符串

json.loads(text)(意思是“load string”)接收一个 JSON 格式的字符串,返回它所表示的 Python 对象:

结果就是一个普通的字典。你可以像访问任何字典一样访问它的键,没有特殊的 JSON 包装,结果上也没有 .parse() 方法。

如果字符串不是有效的 JSON,json.loads 会抛出 json.JSONDecodeError。错误信息中包含出问题的行号和列号,通常足以让你找出漏掉的逗号或没有转义的引号。

把 JSON 写成字符串

json.dumps(data)(意思是“dump string”)做的事情正好相反:接收一个 Python 对象,返回一个 JSON 字符串:

Python 的 True、False 和 None 会被自动转换为 JSON 的 true、false 和 null。数字和字符串保持不变。列表变成数组,字典变成对象。

格式化输出

json.dumps 默认的输出很紧凑,适合网络传输,但人读起来很费劲。传入 indent=2 可以得到更易读的结果:

另外几个值得了解的 dumps 选项:

  • sort_keys=True:按字母顺序对对象的键排序。适合需要确定性输出的场景(配置文件、测试数据、对比差异)。
  • ensure_ascii=False:把非 ASCII 字符(é、ü、中)原样写出,而不是写成 \u 转义序列。对于 UTF-8 文件,这通常是正确的选择。
  • separators=(",", ":"):输出尽可能紧凑。再配合 ensure_ascii=False,就能生成最紧凑的 UTF-8 JSON。

从文件读取 JSON

json.load(file)(不带 s)直接从文件对象读取。常见的写法是和 with open 搭配使用:

import json

with open("config.json") as f:
    config = json.load(f)

print(config["version"])

不需要先把整个文件读成字符串;json.load 会直接从文件对象中读取。

把 JSON 写入文件

json.dump(data, file) 是对应的写文件方法:

import json

data = {"created": "2026-01-01", "items": [1, 2, 3]}

with open("state.json", "w") as f:
    json.dump(data, f, indent=2)

indent 选项在这里同样适用。打开生成的文件,你会看到一个格式整齐的 JSON 文档。

读取 JSON 格式的 API 响应

大多数 HTTP 库给你的是字节或文本,你需要调用 json.loads 把它变成可用的数据:

import json
import urllib.request

with urllib.request.urlopen("https://api.example.com/users/1") as response:
    text = response.read().decode("utf-8")

user = json.loads(text)
print(user["name"])

requests 库(另有专门的页面介绍)可以省掉一步:响应对象上有一个 .json() 方法,会替你调用 json.loads。

JSON 能表示什么,不能表示什么

JSON 的类型系统比 Python 的窄。两个方向的对应关系如下:

PythonJSON
dict对象
list, tuple数组
str字符串
int, float数字
Truetrue
Falsefalse
Nonenull

元组转换后再转回来会变成列表,元组的特性会丢失。集合、自定义类和 datetime 对象默认无法序列化,你会得到 TypeError: Object of type X is not JSON serializable。

处理 datetime 和自定义对象

有两种常见做法。

先转换成可以序列化的结构。 在你自己的代码中完成转换,然后序列化一个普通字典:

传入一个 default= 函数。 遇到不知道如何序列化的值时,json.dumps 会调用它:

读取数据时,你需要自己把这些 ISO 字符串转换回 datetime,因为 JSON 不会记住它们原来是什么类型。

字典经过 JSON 的一次往返

快速验证一下字典能否完整保留:

两者的值相等,但它们是不同的对象。这往往正是你想要的:json.dumps 加 json.loads 是对任何兼容 JSON 的结构做深拷贝的一种简便方法。

一个贴近实际的例子

一个小脚本:加载 JSON 配置,更新一个字段,然后保存回去:

import json
from pathlib import Path

config_path = Path("settings.json")

# Load (with a default if the file doesn't exist).
if config_path.exists():
    config = json.loads(config_path.read_text())
else:
    config = {"theme": "dark", "last_opened": None}

# Update.
config["last_opened"] = "2026-01-15"

# Save, pretty-printed.
config_path.write_text(json.dumps(config, indent=2, ensure_ascii=False))

十几行代码就完成了一个完整的 JSON“读取、修改、写入”流程。

几个好习惯

  • 处理文件时始终用 with open(...)。 JSON 不过是文本,所有文件操作的规则都适用。
  • 给人看的文件优先用 indent=2,比如配置文件、测试数据、导出的数据。对于注重紧凑的网络传输,可以省略。
  • 输出 UTF-8 时设置 ensure_ascii=False,让带重音符号的名字或中文等非拉丁字符保持可读。
  • 解析不是你生成的数据时,用 try/except json.JSONDecodeError 做校验。

下一篇

JSON 处理的是键值数据。同一章的下一个工具是 CSV:Python 对表格格式的内置支持,你遇到的大多数电子表格导出文件用的都是这种格式。

常见问题

Python 中怎么解析 JSON?

JSON 字符串用 json.loads(text),文件对象用 json.load(file)。两者都会返回一个 Python 字典(或列表,取决于 JSON 的内容)。例如:data = json.loads('{"name": "Rosa"}'),此时 data['name'] 是 'Rosa'。

Python 中怎么把字典转换成 JSON?

json.dumps(my_dict) 返回一个 JSON 字符串。json.dump(my_dict, file) 直接写入一个文件对象。传入 indent=2 可以得到格式化的输出:json.dumps(data, indent=2)。

json.loads 和 json.load 有什么区别?

loads(带 s)接收一个字符串。load(不带 s)接收一个文件对象。dumps 和 dump 也是一样。s 代表 string(字符串),这样记最容易分清。

JSON 中怎么处理日期和自定义对象?

JSON 没有日期类型,所以要把日期作为 ISO-8601 字符串传递,读取时再手动解析回来。对于自定义类,可以给 json.dumps 提供一个 default= 函数,让它返回可以转成 JSON 的表示形式;也可以在序列化之前自己把对象转换成 dict。

Coddy 编程语言插图

和 Coddy 一起学编程

开始