Python 与 JSON:全面解析与实战指南
在现代软件开发中,数据交换是核心需求之一。JSON(JavaScript Object Notation)作为一种轻量级、易读易写的数据交换格式,已成为前后端通信、API交互、配置文件存储等场景的事实标准。Python 作为一门强大的脚本语言,内置了 json 模块,提供了简洁高效的 JSON 序列化(Python 对象 → JSON)与反序列化(JSON → Python 对象)能力。
本文将从 JSON 基础语法出发,详细介绍 Python json 模块的核心功能、数据类型转换规则、常见问题处理及最佳实践,并通过大量实例帮助读者快速掌握 Python 与 JSON 的协作技巧。
目录#
- 什么是 JSON?
- 1.1 JSON 简介
- 1.2 JSON 基本语法
- 1.3 JSON 数据类型
- Python 与 JSON:核心模块
json- 2.1 模块简介
- 2.2 核心函数概览
- Python 与 JSON 数据类型转换
- 3.1 类型映射表
- 3.2 转换示例
- 序列化与反序列化实战
- 4.1 序列化:Python 对象 → JSON
- 4.2 反序列化:JSON → Python 对象
- 4.3 处理复杂对象(自定义类)
- 错误处理与常见问题
- 5.1 常见异常类型
- 5.2 错误处理示例
- 最佳实践
- 6.1 格式化与可读性
- 6.2 处理大型 JSON 文件
- 6.3 安全性考虑
- 6.4 非 ASCII 字符处理
- 高级技巧
- 7.1 自定义编码器/解码器
- 7.2 排序键与数据过滤
- 7.3 第三方库推荐
- 总结
- 参考资料
1. 什么是 JSON?#
1.1 JSON 简介#
JSON 是一种基于文本的轻量级数据交换格式,由 Douglas Crockford 于 2001 年提出。它源自 JavaScript,但目前已成为跨语言通用格式,几乎所有编程语言都支持 JSON 解析与生成。其设计目标是易于人类阅读和编写,同时易于机器解析和生成。
1.2 JSON 基本语法#
JSON 语法基于键值对(key-value pairs)和数组(arrays),使用大括号 {} 表示对象,中括号 [] 表示数组,键与值之间用冒号 : 分隔,键值对之间用逗号 , 分隔。
示例:
{
"name": "Alice",
"age": 30,
"is_student": false,
"hobbies": ["reading", "hiking"],
"address": {
"city": "Beijing",
"zipcode": "100000"
}
}1.3 JSON 数据类型#
JSON 支持 6 种基本数据类型:
- 字符串(String):用双引号
"包裹的 Unicode 字符(如"hello")。 - 数字(Number):整数或浮点数(如
42、3.14)。 - 布尔值(Boolean):
true或false。 - 空值(Null):
null(表示空值)。 - 对象(Object):键值对集合,用
{}表示(如{"key": "value"})。 - 数组(Array):有序值列表,用
[]表示(如[1, 2, 3])。
2. Python 与 JSON:核心模块 json#
Python 标准库内置 json 模块,无需额外安装即可使用。它提供了 JSON 序列化与反序列化的核心功能。
2.1 模块简介#
json 模块的设计目标是实现 Python 数据结构与 JSON 格式的双向转换。核心功能围绕序列化(将 Python 对象转为 JSON 字符串或写入文件)和反序列化(将 JSON 字符串或文件解析为 Python 对象)展开。
2.2 核心函数概览#
json 模块的 4 个核心函数:
| 函数 | 功能描述 | 输入类型 | 输出类型 |
|---|---|---|---|
json.dumps() | 将 Python 对象序列化为 JSON 字符串 | Python 对象 | JSON 字符串 |
json.dump() | 将 Python 对象序列化为 JSON 并写入文件 | Python 对象 + 文件对象 | 无(直接写入文件) |
json.loads() | 将 JSON 字符串反序列化为 Python 对象 | JSON 字符串 | Python 对象 |
json.load() | 从文件中读取 JSON 并反序列化为 Python 对象 | 文件对象 | Python 对象 |
说明:函数名中含 s(如 dumps、loads)表示操作字符串(string),不含 s(如 dump、load)表示操作文件对象(file object)。
3. Python 与 JSON 数据类型转换#
Python 与 JSON 的数据类型并非完全一一对应,序列化/反序列化时会自动转换。理解转换规则是避免错误的关键。
3.1 类型映射表#
| Python 类型 | JSON 类型 | 反序列化后 Python 类型 |
|---|---|---|
dict | 对象(Object) | dict |
list, tuple | 数组(Array) | list |
str | 字符串(String) | str |
int, float | 数字(Number) | int/float |
bool (True/False) | true/false | bool |
None | null | None |
注意:
- Python 的
tuple会被序列化为 JSON 数组,反序列化后变为list(丢失元组特性)。 - JSON 没有
set类型,直接序列化set会抛出TypeError。 - Python 的
datetime、decimal.Decimal等非标准类型需自定义转换逻辑。
3.2 转换示例#
Python → JSON(序列化):
import json
data = {
"name": "Bob",
"age": 25,
"is_student": True,
"grades": (90, 85, 95), # tuple 转为 JSON 数组
"address": None
}
json_str = json.dumps(data)
print(json_str)
# 输出:{"name": "Bob", "age": 25, "is_student": true, "grades": [90, 85, 95], "address": null}JSON → Python(反序列化):
json_str = '{"name": "Bob", "age": 25, "grades": [90, 85, 95]}'
data = json.loads(json_str)
print(type(data)) # <class 'dict'>
print(data["grades"]) # [90, 85, 95](list 类型)4. 序列化与反序列化实战#
4.1 序列化:Python 对象 → JSON#
4.1.1 基础用法(dumps)#
json.dumps(obj, **kwargs) 接受 Python 对象并返回 JSON 字符串,支持多种参数控制输出格式:
indent:缩进空格数,用于美化输出(默认无缩进)。ensure_ascii:是否将非 ASCII 字符转义为\uXXXX格式(默认True,设为False可保留原始字符)。sort_keys:是否按键名排序(默认False)。
示例:美化输出
data = {"name": "张三", "age": 30, "hobbies": ["跑步", "游泳"]}
json_str = json.dumps(data, indent=4, ensure_ascii=False, sort_keys=True)
print(json_str)输出:
{
"age": 30,
"hobbies": [
"跑步",
"游泳"
],
"name": "张三"
}4.1.2 写入文件(dump)#
json.dump(obj, fp, **kwargs) 将 Python 对象直接写入文件对象 fp(需以写入模式打开,如 'w')。
示例:
data = {"name": "Alice", "age": 30}
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, indent=4, ensure_ascii=False) # 写入文件并美化生成的 data.json 文件内容:
{
"name": "Alice",
"age": 30
}4.2 反序列化:JSON → Python 对象#
4.2.1 解析字符串(loads)#
json.loads(s, **kwargs) 解析 JSON 字符串 s 并返回 Python 对象。
示例:
json_str = '{"name": "Alice", "age": 30, "hobbies": ["reading"]}'
data = json.loads(json_str)
print(data["name"]) # Alice
print(data["hobbies"][0]) # reading4.2.2 读取文件(load)#
json.load(fp, **kwargs) 从文件对象 fp 中读取 JSON 数据并解析为 Python 对象(需以读取模式打开,如 'r')。
示例:
with open("data.json", "r", encoding="utf-8") as f:
data = json.load(f)
print(data["name"]) # Alice4.3 处理复杂对象(自定义类)#
默认情况下,json 模块无法序列化自定义类实例(如 class Person),需通过 default 参数或自定义编码器实现。
方法 1:使用 default 参数#
通过 default 函数指定非标准类型的转换逻辑(如将对象转为 dict)。
示例:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
person = Person("Charlie", 28)
# 自定义 default 函数:将 Person 实例转为 dict
def person_to_dict(obj):
if isinstance(obj, Person):
return {"name": obj.name, "age": obj.age, "type": "Person"}
raise TypeError(f"无法序列化 {type(obj)} 类型")
json_str = json.dumps(person, default=person_to_dict, indent=4)
print(json_str)输出:
{
"name": "Charlie",
"age": 28,
"type": "Person"
}方法 2:自定义编码器(JSONEncoder 子类)#
继承 json.JSONEncoder 并重写 default 方法,更适合复杂场景。
示例:
class PersonEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Person):
return {"name": obj.name, "age": obj.age, "type": "Person"}
# 其他类型交给父类处理
return super().default(obj)
json_str = json.dumps(person, cls=PersonEncoder, indent=4)
print(json_str) # 输出同上5. 错误处理与常见问题#
5.1 常见异常类型#
json.JSONDecodeError:反序列化时 JSON 格式错误(如语法错误、括号不匹配)。TypeError:序列化时遇到不支持的类型(如set、自定义类实例未处理)。
5.2 错误处理示例#
5.2.1 捕获 JSON 格式错误#
invalid_json = '{"name": "Alice", age: 30}' # 键 "age" 缺少双引号,格式错误
try:
data = json.loads(invalid_json)
except json.JSONDecodeError as e:
print(f"JSON 解析失败:{e}") # 输出:JSON 解析失败:Expecting property name enclosed in double quotes: line 1 column 17 (char 16)5.2.2 捕获不支持的类型错误#
data = {"numbers": {1, 2, 3}} # set 类型不支持序列化
try:
json.dumps(data)
except TypeError as e:
print(f"序列化失败:{e}") # 输出:序列化失败:Object of type set is not JSON serializable6. 最佳实践#
6.1 格式化与可读性#
- 使用
indent参数美化输出,便于调试和阅读(推荐indent=4)。 - 生产环境中可省略
indent以减少 JSON 体积。
6.2 处理大型 JSON 文件#
- 避免使用
loads/dumps一次性加载大文件(可能导致内存溢出),改用load/dump直接操作文件对象,利用 Python 的迭代器特性流式处理。 - 对于超大型 JSON(如 GB 级),可使用
ijson等流式解析库。
6.3 安全性考虑#
- 禁止使用
eval解析 JSON:eval(json_str)存在代码注入风险(如 JSON 中含__import__('os').system('rm -rf /')),必须使用json.loads。 - 不信任的 JSON 数据需验证结构(如使用
pydantic进行数据校验)。
6.4 非 ASCII 字符处理#
- 序列化时设置
ensure_ascii=False,避免非 ASCII 字符(如中文、日文)被转义为\uXXXX格式,保持可读性。 - 写入文件时指定
encoding="utf-8",确保字符正确存储。
7. 高级技巧#
7.1 自定义编码器/解码器#
除了序列化自定义类,还可通过 JSONEncoder 处理特殊类型(如 datetime):
from datetime import datetime
class DateTimeEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat() # 转为 ISO 格式字符串
return super().default(obj)
data = {"event_time": datetime(2023, 10, 1, 12, 0, 0)}
json_str = json.dumps(data, cls=DateTimeEncoder)
print(json_str) # {"event_time": "2023-10-01T12:00:00"}7.2 排序键与数据过滤#
sort_keys=True:按键名升序排列,确保输出一致性(如 API 响应)。skipkeys=True:忽略非字符串类型的键(默认会抛出TypeError)。default参数:过滤或转换特定字段(如隐藏敏感信息)。
7.3 第三方库推荐#
ujson:C 语言实现,比标准json模块快 5-10 倍,适合性能敏感场景。simplejson:功能更丰富(如支持decimal.Decimal),兼容标准json接口。pydantic:结合数据校验与 JSON 解析,适合复杂数据模型(如 API 请求/响应处理)。
8. 总结#
JSON 作为通用数据交换格式,在 Python 生态中占据重要地位。通过 json 模块,我们可以轻松实现 Python 对象与 JSON 的双向转换。本文从基础语法、核心函数、类型转换、实战技巧到最佳实践,全面覆盖了 Python 与 JSON 协作的关键知识点。掌握这些内容后,无论是处理配置文件、对接 API 还是进行数据持久化,都能游刃有余。