Python JSON 全方位解析:序列化、反序列化与实战技巧
在 Python 开发中,JSON(JavaScript Object Notation)是前后端数据交互、跨平台数据传输的核心格式。它轻量、易读且兼容性强,几乎所有编程语言都支持 JSON 解析。本文将结合实战代码,从 JSON 基础概念出发,详细讲解 Python 中 JSON 的序列化(Python 数据转 JSON)、反序列化(JSON 转 Python 数据)、高级配置(美化、特殊类型处理)及文件读写操作,帮助你彻底掌握 JSON 处理技巧。
一、JSON 核心概念与 Python 数据映射
在开始代码实战前,需先明确 JSON 的格式规则及与 Python 数据类型的对应关系 —— 这是正确处理 JSON 的基础。
1.1 JSON 格式规则
JSON 本质是一种字符串格式,有严格的语法要求,常见错误(如单引号、元组)会导致解析失败,核心规则如下:
- 字符串必须用 双引号(
"name"
正确,'name'
错误); - 支持的数据类型:对象(对应 Python 字典)、数组(对应 Python 列表)、字符串、数字、布尔值(
true
/false
)、null
(对应 PythonNone
); - 不支持 Python 特有的类型:集合(
set
)、元组(tuple
)、datetime
等(需特殊处理)。
示例:
// 正确 JSON 格式(对象)
{"name":"mary","age":20,"is_student":true,"hobby":null}// 正确 JSON 格式(数组)
[10, 20, "hello", {"city":"New York"}]
1.2 JSON 与 Python 数据类型映射表
JSON 与 Python 数据类型并非完全一一对应,序列化 / 反序列化时会自动转换,对应关系如下:
Python 数据类型 | JSON 数据类型 | 反序列化后 Python 类型 |
---|---|---|
dict | 对象({} ) | dict |
list /tuple | 数组([] ) | list (元组会转列表) |
str | 字符串 | str |
int /float | 数字 | int /float |
True | true | True |
False | false | False |
None | null | None |
set /datetime | 不支持 | 需自定义处理(见 3.2 节 |
二、基础操作:JSON 序列化与反序列化
Python 内置 json
模块,提供 dumps()
/loads()
两个核心函数,分别实现 “Python 数据转 JSON 字符串” 和 “JSON 字符串转 Python 数据”。
2.1 序列化:json.dumps()
(Python → JSON 字符串)
json.dumps(obj)
接收 Python 数据(如字典、列表),返回对应的 JSON 字符串。下面通过多类型示例演示其用法:
import json# 1. 数字类型(int)
js_num = json.dumps(10)
print("数字序列化:", js_num) # 输出:"10"(JSON 字符串)
print("类型:", type(js_num)) # 输出:<class 'str'># 2. None(对应 JSON null)
js_none = json.dumps(None)
print("\nNone 序列化:", js_none) # 输出:"null"
print("反序列化后类型:", type(json.loads(js_none))) # 输出:<class 'NoneType'># 3. 布尔值(True/False)
js_bool = json.dumps(True)
print("\n布尔值序列化:", js_bool) # 输出:"true"(JSON 小写)
print("反序列化后值:", json.loads(js_bool)) # 输出:True# 4. 列表(含混合类型)
js_list = json.dumps([10, 20, 'hello'])
print("\n列表序列化:", js_list) # 输出:"[10, 20, \"hello\"]"(双引号转义)
print("反序列化后:", json.loads(js_list)) # 输出:[10, 20, 'hello']# 5. 字典(key 需为字符串/数字,不支持元组)
js_dict = json.dumps({'name': 'mary', 'age': 20, None: 'hello'})
print("\n字典序列化:", js_dict) # 输出:"{"name":"mary","age":20,"null":"hello"}"(None 转 null 作为 key)
print("反序列化后:", json.loads(js_dict)) # 输出:{'name': 'mary', 'age': 20, 'null': 'hello'}# 6. 嵌套结构(列表+字典)
js_nested = json.dumps([{'name': 'mary', 'age': 20}, {'name': 'tom', 'age': 30}])
print("\n嵌套结构序列化:", js_nested) # 输出:"[{"name":"mary","age":20},{"name":"tom","age":30}]"
print("反序列化后:", json.loads(js_nested)) # 输出:[{'name': 'mary', 'age': 20}, {'name': 'tom', 'age': 30}]# ❌ 不支持的类型:集合(会抛 TypeError)
# js_set = json.dumps({12, 22, 'world'}) # 报错:TypeError: Object of type set is not JSON serializable
2.2 反序列化:json.loads()
(JSON 字符串 → Python 数据)
json.loads(json_str)
接收 JSON 格式的字符串,返回对应的 Python 数据。需注意:输入必须是严格的 JSON 字符串(双引号、无非法类型)。
import json# 1. JSON 字符串(对象)转 Python 字典
json_str1 = '{"name":"张三","age":20,"is_student":true,"hobby":null}'
py_dict = json.loads(json_str1)
print("JSON 对象转字典:", py_dict)
print("类型:", type(py_dict)) # 输出:<class 'dict'># 2. JSON 字符串(数组)转 Python 列表
json_str2 = '[10, 20, "hello", {"city":"北京"}]'
py_list = json.loads(json_str2)
print("\nJSON 数组转列表:", py_list)
print("类型:", type(py_list)) # 输出:<class 'list'># 3. 特殊值反序列化(null → None,true → True)
json_str3 = '{"score":null, "passed":false}'
py_data = json.loads(json_str3)
print("\n特殊值反序列化:", py_data) # 输出:{'score': None, 'passed': False}
三、高级配置:美化、特殊类型处理
json.dumps()
提供多个可选参数,支持 JSON 美化、中文显示、特殊类型(如 set
/datetime
)序列化,满足复杂场景需求。
3.1 常用配置参数(美化、中文、排序)
通过 ensure_ascii
、indent
、separators
、sort_keys
四个参数,可自定义 JSON 输出格式:
参数名 | 作用说明 |
---|---|
ensure_ascii | 布尔值,默认 True (中文转义为 \uXXXX ),设为 False 可显示中文 |
indent | 整数,JSON 缩进空格数(美化输出),默认 None (紧凑格式) |
separators | 元组 (item_sep, key_sep) ,指定分隔符(默认 (', ', ': ') ) |
sort_keys | 布尔值,默认 False ,设为 True 按字典 key 升序排列 |
示例:
import json# 原始 Python 数据(含中文)
student = {'name': '张三', 'age': 20, 'sex': '男', 'score': 95}# 应用高级配置
js_pretty = json.dumps(student,ensure_ascii=False, # 显示中文(不转义)indent=4, # 缩进 4 个空格(美化)separators=(',', ':'), # 列表元素用 ',' 分隔,字典 key-value 用 ':' 分隔(无空格)sort_keys=True # 按 key 升序排列(age < name < score < sex)
)print("美化后的 JSON:")
print(js_pretty)
输出结果(格式清晰,中文正常显示):
{"age":20,"name":"张三","score":95,"sex":"男"
}
3.2 特殊类型处理:default
参数
JSON 不支持 Python 的 set
、datetime
等类型,直接序列化会抛 TypeError
。此时需通过 default
参数指定自定义处理函数,将特殊类型转换为 JSON 支持的类型(如 set
转 list
,datetime
转字符串)。
案例:处理 set
和 datetime
类型
import json
from datetime import datetime# 含特殊类型的 Python 数据
data = {'name': 'mary','hobbys': {'打球', '编程'}, # set 类型(JSON 不支持)'borndate': datetime(2003, 2, 18) # datetime 类型(JSON 不支持)
}
list_data = [10, 'hello', {'唱歌', '跑步'}] # 列表含 set# 自定义处理函数:接收无法序列化的对象(obj),返回 JSON 支持的类型
def handle_special_types(obj):# 处理 set 类型:转为 listif isinstance(obj, set):return list(obj)# 处理 datetime 类型:转为字符串(如 "2003-02-18")if isinstance(obj, datetime):return obj.strftime('%Y-%m-%d')# 其他未处理类型:抛异常(可选)raise TypeError(f"不支持的类型:{type(obj)}")# 1. 序列化含特殊类型的字典
js_data = json.dumps(data,ensure_ascii=False,default=handle_special_types # 指定自定义处理函数
)
print("处理特殊类型的 JSON(字典):")
print(js_data)
print("反序列化后:", json.loads(js_data)) # set 已转为 list,datetime 已转为字符串# 2. 序列化含特殊类型的列表
js_list = json.dumps(list_data,ensure_ascii=False,default=handle_special_types
)
print("\n处理特殊类型的 JSON(列表):")
print(js_list)
print("反序列化后:", json.loads(js_list))
输出结果:
处理特殊类型的 JSON(字典):
{"name":"mary","hobbys":["打球","编程"],"borndate":"2003-02-18"}
反序列化后: {'name': 'mary', 'hobbys': ['打球', '编程'], 'borndate': '2003-02-18'}处理特殊类型的 JSON(列表):
[10,"hello",["唱歌","跑步"]]
反序列化后: [10, 'hello', ['唱歌', '跑步']]
四、文件操作:JSON 与文件的交互
实际开发中,JSON 数据常需写入文件(如配置文件)或从文件读取。json
模块提供 dump()
和 load()
函数,直接实现 “Python 数据 ↔ 文件” 的交互,无需手动处理字符串读写。
4.1 序列化到文件:json.dump()
json.dump(obj, file_obj)
将 Python 数据直接写入文件(需以文本模式 w
打开文件),等价于 file.write(json.dumps(obj))
,但更简洁。
import json# 待写入文件的 Python 数据
user_list = [{'name': '张三', 'age': 20, 'city': '上海'},{'name': 'tom', 'age': 30, 'city': 'London'}
]# 方式1:用 json.dump() 直接写入(推荐)
with open(r'.\data\users.json', mode='w', encoding='utf-8') as f:json.dump(user_list,f,ensure_ascii=False, # 显示中文indent=2 # 美化格式)
print("JSON 数据写入文件完成!")# 方式2:先 dumps() 转字符串,再 write()(等价,略繁琐)
# with open(r'.\data\users2.json', mode='w', encoding='utf-8') as f:
# js_str = json.dumps(user_list, ensure_ascii=False, indent=2)
# f.write(js_str)
4.2 从文件反序列化:json.load()
json.load(file_obj)
从文件中读取 JSON 数据并直接转为 Python 数据,等价于 json.loads(file.read())
,简化代码。
import json# 方式1:用 json.load() 直接读取(推荐)
with open(r'.\data\users.json', mode='r', encoding='utf-8') as f:py_data = json.load(f)
print("从文件读取的 Python 数据:")
print(py_data)
print("类型:", type(py_data)) # 输出:<class 'list'># 方式2:先 read() 读字符串,再 loads()(等价)
# with open(r'.\data\users.json', mode='r', encoding='utf-8') as f:
# js_str = f.read()
# py_data2 = json.loads(js_str)
# print("\n方式2读取:", py_data2)
从文件读取的 Python 数据:
[{'name': '张三', 'age': 20, 'city': '上海'}, {'name': 'tom', 'age': 30, 'city': 'London'}]
类型: <class 'list'>
五、常见问题与解决方案
在 JSON 处理中,初学者常遇到中文乱码、特殊类型报错等问题,以下是高频问题的解决方法。
5.1 中文乱码(\uXXXX
转义)
问题:序列化含中文的数据时,输出为 \u5f20\u4e09
等转义字符,而非中文。
原因:json.dumps()
默认 ensure_ascii=True
,会将非 ASCII 字符转义。
解决:设置 ensure_ascii=False
,并指定文件编码为 utf-8
(写入文件时)。
# 正确示例
data = {'name': '李四', 'age': 25}
js = json.dumps(data, ensure_ascii=False)
print(js) # 输出:{"name":"李四","age":25}(中文正常显示)
5.2 特殊类型序列化报错(TypeError
)
问题:序列化 set
/datetime
等类型时,报错 TypeError: Object of type XXX is not JSON serializable
。
解决:通过 default
参数指定自定义处理函数,将特殊类型转为 JSON 支持的类型(如 set
转 list
,datetime
转字符串),见 3.2 节案例。
5.3 JSON 字符串格式错误(JSONDecodeError
)
问题:反序列化时,报错 json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
。
常见原因:
- JSON 字符串用单引号(如
{'name':'mary'}
); - 字符串含多余逗号(如
[10, 20, ]
); - 文件读取时编码错误(如用
gbk
读取utf-8
文件)。
解决:
- 确保 JSON 字符串用双引号;
- 检查 JSON 语法(无多余逗号、括号匹配);
- 读取文件时指定正确编码(如
encoding='utf-8'
)。
六、总结
本文覆盖了 Python JSON 处理的全流程,核心要点总结如下:
1. 核心函数
函数 | 功能 | 适用场景 |
---|---|---|
json.dumps() | Python 数据 → JSON 字符串 | 内存中数据交互(如接口请求) |
json.loads() | JSON 字符串 → Python 数据 | 内存中数据解析(如接口响应) |
json.dump() | Python 数据 → JSON 文件 | 数据持久化(写入配置文件) |
json.load() | JSON 文件 → Python 数据 | 读取配置文件 |
2. 关键参数
ensure_ascii=False
:显示中文,避免转义;indent=N
:美化 JSON 格式,便于调试;default=函数
:处理set
/datetime
等特殊类型;sort_keys=True
:按字典 key 排序,输出更规范。
3. 最佳实践
- 处理中文时,始终设置
ensure_ascii=False
并指定encoding='utf-8'
; - 写入文件优先用
json.dump()
,读取文件优先用json.load()
(简化代码); - 遇到特殊类型时,通过
default
参数自定义处理逻辑,避免直接修改原始数据; - 反序列化前,确保输入是严格的 JSON 格式(双引号、无语法错误)。
掌握这些技巧后,你可以轻松应对前后端数据交互、配置文件读写、跨平台数据传输等场景,JSON 处理将成为你的开发利器。