Python 与 JSON:全面解析与实战指南

在现代软件开发中,数据交换是核心需求之一。JSON(JavaScript Object Notation)作为一种轻量级、易读易写的数据交换格式,已成为前后端通信、API交互、配置文件存储等场景的事实标准。Python 作为一门强大的脚本语言,内置了 json 模块,提供了简洁高效的 JSON 序列化(Python 对象 → JSON)与反序列化(JSON → Python 对象)能力。

本文将从 JSON 基础语法出发,详细介绍 Python json 模块的核心功能、数据类型转换规则、常见问题处理及最佳实践,并通过大量实例帮助读者快速掌握 Python 与 JSON 的协作技巧。

目录#

  1. 什么是 JSON?
    • 1.1 JSON 简介
    • 1.2 JSON 基本语法
    • 1.3 JSON 数据类型
  2. Python 与 JSON:核心模块 json
    • 2.1 模块简介
    • 2.2 核心函数概览
  3. Python 与 JSON 数据类型转换
    • 3.1 类型映射表
    • 3.2 转换示例
  4. 序列化与反序列化实战
    • 4.1 序列化:Python 对象 → JSON
    • 4.2 反序列化:JSON → Python 对象
    • 4.3 处理复杂对象(自定义类)
  5. 错误处理与常见问题
    • 5.1 常见异常类型
    • 5.2 错误处理示例
  6. 最佳实践
    • 6.1 格式化与可读性
    • 6.2 处理大型 JSON 文件
    • 6.3 安全性考虑
    • 6.4 非 ASCII 字符处理
  7. 高级技巧
    • 7.1 自定义编码器/解码器
    • 7.2 排序键与数据过滤
    • 7.3 第三方库推荐
  8. 总结
  9. 参考资料

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/falsebool
NonenullNone

注意:

  • 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])  # reading

4.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"])  # Alice

4.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 serializable

6. 最佳实践#

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 还是进行数据持久化,都能游刃有余。

9. 参考资料#