前言
在日常开发中,JSON(JavaScript Object Notation)是数据交换最常用的格式之一。Python 内置的 json 模块提供了完整的 JSON 与 Python 数据类型之间的转换能力。本文将系统总结 JSON 字符串 ↔ Python 字典/列表 的相互转换知识,帮助你彻底掌握这一技能。
一、核心对应关系
理解类型映射是掌握转换的关键:
| JSON 类型 | Python 类型 |
|---|---|
object {} |
dict(字典) |
array [] |
list(列表) |
string "..." |
str(字符串) |
| number(整数) | int |
| number(小数) | float |
true / false |
True / False |
null |
None |
重要规律:
-
JSON 的 对象 对应 Python 的 字典
-
JSON 的 数组 对应 Python 的 列表
-
Python 的字典/列表互相嵌套时,转换后依然是嵌套结构
二、四个核心函数
json 模块中最常用的四个函数,记住一句话:
带
s的操作字符串,不带s的操作文件。
| 函数 | 方向 | 输入 | 输出 |
|---|---|---|---|
json.loads() |
JSON → Python | 字符串 | dict / list |
json.dumps() |
Python → JSON | dict / list | 字符串 |
json.load() |
JSON → Python | 文件对象 | dict / list |
json.dump() |
Python → JSON | dict / list | 写入文件 |
三、JSON 字符串 → 字典 / 列表
3.1 JSON 对象转字典
python
python
import json
json_str = '{"name": "小明", "age": 18, "city": "北京"}'
result = json.loads(json_str)
print(result)
print(type(result))
输出:
text
{'name': '小明', 'age': 18, 'city': '北京'}
<class 'dict'>
3.2 JSON 数组转列表
python
python
import json
json_str = '[1, 2, 3, "hello", true, null]'
result = json.loads(json_str)
print(result)
print(type(result))
输出:
text
python
[1, 2, 3, 'hello', True, None]
<class 'list'>
3.3 嵌套结构转换
python
python
import json
json_str = '''
{
"users": [
{"name": "小明", "age": 18},
{"name": "小红", "age": 20}
],
"total": 2
}
'''
result = json.loads(json_str)
print(result["users"][0]["name"]) # 小明
print(result["total"]) # 2
嵌套结构会按照对应关系逐层转换。
四、字典 / 列表 → JSON 字符串
4.1 字典转 JSON
python
python
import json
data = {"name": "小明", "age": 18, "city": "北京"}
json_str = json.dumps(data, ensure_ascii=False)
print(json_str)
print(type(json_str))
输出:
python
text
{"name": "小明", "age": 18, "city": "北京"}
<class 'str'>
4.2 列表转 JSON
python
python
import json
data = [1, 2, 3, "hello", True, None]
json_str = json.dumps(data, ensure_ascii=False)
print(json_str)
'''输出:'''
text
[1, 2, 3, "hello", true, null]
注意:Python 的
True/False/None会变成 JSON 的true/false/null。
4.3 嵌套结构转换
python
python
import json
data = {
"users": [
{"name": "小明", "age": 18},
{"name": "小红", "age": 20}
],
"total": 2
}
json_str = json.dumps(data, ensure_ascii=False, indent=2)
print(json_str)
输出:
python
json
{
"users": [
{
"name": "小明",
"age": 18
},
{
"name": "小红",
"age": 20
}
],
"total": 2
}
五、dumps 常用参数详解
json.dumps() 支持多个实用参数,掌握它们能让输出更符合需求。
5.1 ensure_ascii
控制非 ASCII 字符是否转义。
python
python
data = {"city": "北京"}
# 默认 True,中文被转义
print(json.dumps(data))
# {"city": "\u5317\u4eac"}
# 设为 False,中文原样输出(推荐)
print(json.dumps(data, ensure_ascii=False))
# {"city": "北京"}
建议:只要包含中文,都加上 ensure_ascii=False。
5.2 indent
美化输出,设置缩进空格数。
python
python
data = {"name": "小明", "age": 18}
print(json.dumps(data, ensure_ascii=False, indent=2))
输出:
json
python
{
"name": "小明",
"age": 18
}
indent=None(默认)时输出为紧凑的一行。
5.3 sort_keys
按键名排序输出。
python
python
data = {"c": 3, "a": 1, "b": 2}
print(json.dumps(data, sort_keys=True))
# {"a": 1, "b": 2, "c": 3}
5.4 separators
自定义分隔符,用于压缩输出。
python
python
data = {"a": 1, "b": 2}
# 默认: (', ', ': ')
# 压缩: (',', ':')
print(json.dumps(data, separators=(',', ':')))
# {"a":1,"b":2}
5.5 参数速查表
| 参数 | 说明 | 常用值 |
|---|---|---|
ensure_ascii |
是否转义非 ASCII 字符 | False(中文场景) |
indent |
缩进空格数 | 2 或 4 |
sort_keys |
按键排序 | True / False |
separators |
分隔符 | (',', ':') |
default |
处理无法序列化的对象 | 自定义函数 |
六、文件读写操作
处理文件时用 json.load() 和 json.dump()(不带 s)。
6.1 从文件读取 JSON
python
python
import json
with open("data.json", "r", encoding="utf-8") as f:
data = json.load(f)
print(data)
print(type(data))
6.2 写入 JSON 到文件
python
python
import json
data = {"name": "小明", "age": 18, "hobbies": ["读书", "游泳"]}
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
务必指定
encoding="utf-8",否则中文可能乱码。
七、进阶技巧
7.1 处理特殊类型(如 datetime)
JSON 默认不支持日期、自定义对象等类型,可通过 default 参数处理。
python
python
import json
from datetime import datetime
def default_handler(obj):
if isinstance(obj, datetime):
return obj.strftime("%Y-%m-%d %H:%M:%S")
raise TypeError(f"无法序列化: {type(obj)}")
data = {"time": datetime.now()}
print(json.dumps(data, default=default_handler, ensure_ascii=False))
# {"time": "2024-01-01 12:00:00"}
7.2 object_hook 自定义解析
json.loads() 支持 object_hook,可在解析时对字典做处理。
python
python
import json
def hook(d):
if "age" in d:
d["age"] = int(d["age"])
return d
json_str = '{"name": "小明", "age": "18"}'
result = json.loads(json_str, object_hook=hook)
print(result) # {'name': '小明', 'age': 18}
7.3 深拷贝的替代用法
利用 JSON 转换可以实现简单的深拷贝(仅限基础类型):
python
python
import json
original = {"a": [1, 2, 3], "b": {"c": 4}}
copy = json.loads(json.dumps(original))
copy["a"].append(4)
print(original["a"]) # [1, 2, 3] 原数据不受影响
print(copy["a"]) # [1, 2, 3, 4]
7.4 判断字符串是否为合法 JSON
python
python
import json
def is_valid_json(s):
try:
json.loads(s)
return True
except json.JSONDecodeError:
return False
print(is_valid_json('{"a": 1}')) # True
print(is_valid_json('{a: 1}')) # False
八、常见错误与注意事项
8.1 单引号不是合法 JSON
JSON 标准要求字符串和键名使用双引号。
python
python
import json
# 错误:单引号
json.loads("{'name': '小明'}")
# json.decoder.JSONDecodeError
# 正确:双引号
json.loads('{"name": "小明"}')
8.2 尾随逗号不合法
python
python
# 错误
json.loads('{"a": 1, "b": 2,}')
# 正确
json.loads('{"a": 1, "b": 2}')
8.3 元组会被转为列表
python
python
import json
data = (1, 2, 3)
print(json.dumps(data)) # [1, 2, 3]
print(type(json.loads("[1,2,3]"))) # <class 'list'>
8.4 字典的键必须是字符串
JSON 对象的键必须是字符串,非字符串键会被转换。
python
python
import json
data = {1: "a", 2: "b"}
print(json.dumps(data)) # {"1": "a", "2": "b"}
8.5 精度丢失问题
浮点数在转换中可能出现精度问题,涉及金额等高精度场景建议用字符串传输。
8.6 异常处理
python
python
import json
try:
data = json.loads('{"a": 1}')
except json.JSONDecodeError as e:
print(f"解析失败: {e}")
九、完整示例:综合运用
python
python
import json
# 原始 Python 数据(字典 + 列表嵌套)
data = {
"class": "三年二班",
"students": [
{"name": "小明", "age": 18, "scores": [90, 85, 88]},
{"name": "小红", "age": 20, "scores": [95, 92, 98]}
],
"count": 2
}
# 1. 转换为 JSON 字符串
json_str = json.dumps(data, ensure_ascii=False, indent=2)
print("=== JSON 字符串 ===")
print(json_str)
# 2. 保存到文件
with open("students.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
# 3. 从文件读取
with open("students.json", "r", encoding="utf-8") as f:
loaded = json.load(f)
# 4. 访问数据
print("\n=== 访问数据 ===")
print(loaded["class"])
for s in loaded["students"]:
print(f'{s["name"]} 平均分: {sum(s["scores"]) / len(s["scores"]):.2f}')
十、总结
核心口诀
-
JSON 对象 ↔ dict,JSON 数组 ↔ list
-
带
s操作字符串,不带s操作文件 -
load是解析(JSON→Python),dump是序列化(Python→JSON) -
中文场景记得加
ensure_ascii=False -
文件读写记得指定
encoding="utf-8"
转换方向速查
| 需求 | 使用函数 |
|---|---|
| JSON 字符串 → 字典/列表 | json.loads() |
| 字典/列表 → JSON 字符串 | json.dumps() |
| JSON 文件 → 字典/列表 | json.load() |
| 字典/列表 → JSON 文件 | json.dump() |
掌握以上内容,基本可以应对 Python 开发中 99% 的 JSON 转换场景。如果涉及超大文件、高精度数值或高性能需求,可以考虑 orjson、ujson 等第三方库作为补充。
如果本文对你有帮助,欢迎点赞、收藏、评论三连支持一下! 🎉