pin_drop当前位置:知识文库 ❯ 图文

JSONEncoder详解 - Python自定义JSON序列化完整指南

JSONEncoder - Python自定义JSON编码器详解

概述

json.JSONEncoder 是 json 模块中用于 JSON 编码的基类,它定义了将 Python 对象序列化为 JSON 的默认行为。通过继承 JSONEncoder 并重写 default() 方法,可以扩展编码器以支持自定义类型(如 datetime、Decimal、自定义类等),实现可复用的序列化逻辑。JSONEncoder 适用于项目中需要统一处理特定类型序列化的场景。


语法

代码示例

import json

class CustomEncoder(json.JSONEncoder):
    def default(self, obj):
        # 自定义序列化逻辑
        if isinstance(obj, SomeType):
            return convertible_value
        return super().default(obj)

# 使用自定义编码器
json_str = json.dumps(data, cls=CustomEncoder)

参数说明

JSONEncoder构造函数

参数 类型 默认值 说明
skipkeys bool False 跳过非字符串键
ensure_ascii bool True 转义非ASCII字符
check_circular bool True 检查循环引用
allow_nan bool True 允许NaN/Infinity
sort_keys bool False 按键排序
indent int/str None 缩进设置
separators tuple None 分隔符设置
default callable None 默认转换函数

需要重写的方法

方法 说明
default(self, obj) 处理无法序列化的对象,返回可序列化值或引发TypeError

返回值

JSONEncoder 的 encode() 方法返回 JSON 字符串 str。iterencode() 方法返回生成器,逐部分生成 JSON 字符串。


代码示例

示例1:支持datetime的自定义编码器

代码示例

import json
from datetime import datetime, date

class DateTimeEncoder(json.JSONEncoder):
    """支持datetime和date的编码器"""

    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.isoformat()
        elif isinstance(obj, date):
            return obj.isoformat()
        return super().default(obj)

# 使用自定义编码器
data = {
    "event": "会议",
    "created_at": datetime(2024, 1, 15, 14, 30, 0),
    "deadline": date(2024, 6, 30),
}

result = json.dumps(data, cls=DateTimeEncoder, ensure_ascii=False, indent=2)
print(result)

输出:

代码示例

{
  "event": "会议",
  "created_at": "2024-01-15T14:30:00",
  "deadline": "2024-06-30"
}

示例2:多类型支持编码器

代码示例

import json
from decimal import Decimal
from datetime import datetime, date
from enum import Enum

class UniversalEncoder(json.JSONEncoder):
    """通用多类型编码器"""

    def default(self, obj):
        if isinstance(obj, datetime):
            return {"__datetime__": obj.isoformat()}
        elif isinstance(obj, date):
            return {"__date__": obj.isoformat()}
        elif isinstance(obj, Decimal):
            return {"__decimal__": str(obj)}
        elif isinstance(obj, Enum):
            return {"__enum__": obj.value}
        elif isinstance(obj, set):
            return {"__set__": list(obj)}
        elif isinstance(obj, bytes):
            return {"__bytes__": obj.decode('utf-8')}
        return super().default(obj)

# 测试多种类型
class Status(Enum):
    ACTIVE = "active"
    INACTIVE = "inactive"

data = {
    "price": Decimal("19.99"),
    "status": Status.ACTIVE,
    "tags": {"python", "json"},
    "data": b"hello",
}

result = json.dumps(data, cls=UniversalEncoder, ensure_ascii=False, indent=2)
print(result)

输出:

代码示例

{
  "price": {
    "__decimal__": "19.99"
  },
  "status": {
    "__enum__": "active"
  },
  "tags": {
    "__set__": [
      "python",
      "json"
    ]
  },
  "data": {
    "__bytes__": "hello"
  }
}

示例3:自定义对象序列化

代码示例

import json

class User:
    """自定义用户类"""
    def __init__(self, name, age, email):
        self.name = name
        self.age = age
        self.email = email

    def to_dict(self):
        return {"name": self.name, "age": self.age, "email": self.email}

class UserEncoder(json.JSONEncoder):
    """用户对象编码器"""

    def default(self, obj):
        if isinstance(obj, User):
            return {"__user__": obj.to_dict()}
        return super().default(obj)

# 使用
user = User("张三", 25, "zhangsan@example.com")
data = {
    "user": user,
    "message": "用户注册成功",
}

result = json.dumps(data, cls=UserEncoder, ensure_ascii=False, indent=2)
print(result)

输出:

代码示例

{
  "user": {
    "__user__": {
      "name": "张三",
      "age": 25,
      "email": "zhangsan@example.com"
    }
  },
  "message": "用户注册成功"
}

实际应用场景

  • 统一序列化策略:在项目中定义一个全局编码器,统一处理 datetime、Decimal 等类型的序列化

  • 自定义对象序列化:为业务对象定义 JSON 表示方式,实现对象到 JSON 的自动转换

  • API 响应格式化:在 Web 框架中注册自定义编码器,统一处理响应数据的序列化


注意事项

注意1:重写 default() 方法时,对于无法处理的类型必须调用 super().default(obj),否则会丢失默认的错误处理逻辑。

注意2:default() 方法返回的值必须是 JSON 可序列化的类型(dict、list、str、int、float、bool、None),否则会递归调用 default()。

注意3:使用类型标记(如 __datetime__)时,需确保对应的解码器能识别这些标记,否则反序列化后类型信息会丢失。

提示:JSONEncoder 的 encode() 和 iterencode() 方法可以直接调用,无需通过 json.dumps()。iterencode() 适合处理大型数据,逐块生成 JSON。


相关方法对比

特性 JSONEncoder子类 default参数 手动转换 第三方库(orjson)
可复用性 高 低 低 高
类型标记 支持 不支持 可选 内置
维护成本 低 低 高 低
性能 标准 标准 标准 更快
灵活性 高 中等 高 有限
推荐场景 项目级统一 临时使用 简单场景 高性能需求

小结

  • JSONEncoder 通过继承和重写 default() 方法实现自定义类型的序列化

  • 始终在 default() 末尾调用 super().default(obj) 处理未知类型

  • 使用类型标记(如 __datetime__)可以在解码时恢复原始类型

  • 项目中推荐定义统一的编码器类,避免在每次 dumps() 时重复指定 default 参数


练习题

练习1

编写一个 ComplexEncoder,支持序列化 Python 的 complex 复数类型,格式为 {"__complex__": [real, imag]}。

练习2

编写配套的 complex_decoder 函数(作为 object_hook),实现复数类型的完整序列化/反序列化循环。

练习3

编写一个 DataclassEncoder,自动将 @dataclass 装饰的类实例序列化为字典,使用 dataclasses.asdict() 实现。

常见问题

如何创建支持datetime的JSON编码器?

继承json.JSONEncoder类并重写default()方法,在方法中检查对象是否为datetime或date类型,如果是则调用isoformat()方法转换为字符串格式。

为什么要在default()方法末尾调用super().default(obj)?

调用super().default(obj)可以处理未知的类型,抛出标准的TypeError异常。如果不这样做,遇到无法处理的类型时会导致不可预期的行为。

什么是类型标记?有什么优缺点?

类型标记是在序列化时使用特殊键名(如__datetime__)标记数据类型的方法。优点是可以完整保留类型信息用于反序列化;缺点是不是JSON标准做法,与其他工具不兼容。

JSONEncoder和default参数有什么区别?

JSONEncoder子类是可复用的类,可以在项目多个地方使用;default参数适合临时使用,每次调用dumps()都需要传入。项目级统一处理推荐使用JSONEncoder子类。

标签: JSONEncoder 自定义序列化 default方法 datetime编码 类型标记 Python教程

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: json.load详解 - Python从文件读取JSON数据完整指南 下一篇: JSONDecoder详解 - Python自定义反序列化完整指南

poll相关推荐