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

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

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

概述

json.JSONEncoderjson 模块中用于 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

返回值

JSONEncoderencode() 方法返回 JSON 字符串 striterencode() 方法返回生成器,逐部分生成 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),否则会丢失默认的错误处理逻辑。

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

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

提示JSONEncoderencode()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相关推荐