文章目录
- # 步骤1:将dataclass转成普通字典 user_dict = asdict(test_user) # 步骤2:处理非JSON原生类型(如datetime) user_dict[“register_time”] = user_dict[“register_time”].isoformat() # 步骤3:序列化为JSON字符串 user_json = json.dumps(user_dict, ensure_ascii=False, indent=2) print(user_json)
- { “id”: 1001, “name”: “张三”, “age”: 28, “register_time”: “2026-01-19T10:30:00”, “address”: { “province”: “浙江省”, “city”: “杭州市”, “detail”: “西湖区XX路” }, “tags”: [“VIP”, “新用户”] }
- asdict(test_user):核心函数,将数据类实例递归转换为普通字典(嵌套的Address也会被转成字典); ensure_ascii=False:保留中文等非 ASCII 字符,避免转成uXXXX编码; indent=2:格式化输出,提升可读性; 需手动处理datetime等非 JSON 原生类型(JSON 仅支持字符串 / 数字 / 布尔 / 列表 / 字典 /null)。
- class DataclassJSONEncoder(json.JSONEncoder): “””自定义JSON编码器,支持dataclass和常见非基础类型””” def default(self, obj): # 第一步:处理dataclass实例 if hasattr(obj, “__dataclass_fields__”): # 判断是否是dataclass return asdict(obj) # 第二步:处理datetime类型 if isinstance(obj, datetime): return obj.isoformat() # 第三步:其他类型交给父类处理(会抛出标准异常) return super().default(obj) # 直接使用自定义编码器序列化 user_json = json.dumps( test_user, cls=DataclassJSONEncoder, # 指定自定义编码器 ensure_ascii=False, indent=2 ) print(user_json)
- 继承json.JSONEncoder并重写default方法:这是json模块扩展序列化规则的标准方式; __dataclass_fields__:dataclass 实例的内置属性,用于判断是否为数据类; 可扩展:如需支持date/UUID等类型,只需在default方法中新增isinstance判断即可; 无需手动转字典,直接序列化数据类实例,代码更简洁。
- pip install pydantic
- from pydantic import BaseModel from datetime import datetime # 替换原生dataclass为pydantic.BaseModel class Address(BaseModel): province: str city: str detail: str = “” class User(BaseModel): id: int name: str age: int register_time: datetime address: Address tags: list[str] = None # 可选:自定义JSON序列化配置(如datetime格式) class Config: json_encoders = { datetime: lambda v: v.strftime(“%Y-%m-%d %H:%M:%S”) # 自定义时间格式 } # 创建实例(pydantic会自动验证字段类型) test_user = User( id=1001, name=”张三”, age=28, register_time=datetime(2026, 1, 19, 10, 30), address=Address(province=”浙江省”, city=”杭州市”, detail=”西湖区XX路”), tags=[“VIP”, “新用户”] ) # 原生支持JSON转换(一行搞定) user_json = test_user.json(ensure_ascii=False, indent=2) print(user_json)
- { “id”: 1001, “name”: “张三”, “age”: 28, “register_time”: “2026-01-19 10:30:00”, “address”: { “province”: “浙江省”, “city”: “杭州市”, “detail”: “西湖区XX路” }, “tags”: [“VIP”, “新用户”] }
- 原生支持json()方法:无需手动写编码器,开箱即用; 自动数据验证:创建实例时会校验字段类型(如age传字符串会直接报错); 灵活配置:通过Config.json_encoders自定义非基础类型的序列化规则; 支持嵌套、可选字段、默认值等,完全兼容原生 dataclass 的用法,且功能更强。
目录
- 前置准备:定义测试数据类
- 方法 1:基础版 -dataclasses.asdict手动转换(简单场景)
- 代码实现:
- 输出结果:
- 关键解释:
- 方法 2:进阶版 – 自定义JSONEncoder(通用可扩展)
- 代码实现:
- 关键解释:
- 方法 3:优化版 – 封装成工具函数(复用性拉满)
- 方法 4:高级版 – 使用pydantic(生产环境推荐)
- 前置依赖:
- 代码实现:
- 输出结果(时间格式自定义后):
- 关键优势:
- 总结
Python 标准库的json模块默认无法直接序列化自定义的dataclass实例(会报Object of type XXX is not JSON serializable),核心原因是json只支持基础类型(str/int/list/dict 等)。下面我会从基础到进阶给出 4 种优雅的转换方法,覆盖简单场景到生产级复杂场景,你可根据需求选择。
先定义一个典型的嵌套数据类,作为后续转换的示例:
from dataclasses import dataclass, asdict
import json
from datetime import datetime # 包含非基础类型,模拟真实场景
# 嵌套子数据类
@dataclass
class Address:
province: str
city: str
detail: str = "" # 可选字段
# 主数据类
@dataclass
class User:
id: int
name: str
age: int
register_time: datetime # 非JSON原生类型
address: Address # 嵌套数据类
tags: list[str] = None # 可选列表字段
# 创建测试实例
test_user = User(
id=1001,
name="张三",
age=28,
register_time=datetime(2026, 1, 19, 10, 30),
address=Address(province="浙江省", city="杭州市", detail="西湖区XX路"),
tags=["VIP", "新用户"]
)
这是最基础的优雅方式,利用dataclasses内置的asdict方法将数据类转成字典,再用json.dumps序列化。
# 步骤1:将dataclass转成普通字典
user_dict = asdict(test_user)
# 步骤2:处理非JSON原生类型(如datetime)
user_dict["register_time"] = user_dict["register_time"].isoformat()
# 步骤3:序列化为JSON字符串
user_json = json.dumps(user_dict, ensure_ascii=False, indent=2)
print(user_json)
{
"id": 1001,
"name": "张三",
"age": 28,
"register_time": "2026-01-19T10:30:00",
"address": {
"province": "浙江省",
"city": "杭州市",
"detail": "西湖区XX路"
},
"tags": ["VIP", "新用户"]
}
asdict(test_user):核心函数,将数据类实例递归转换为普通字典(嵌套的Address也会被转成字典);
ensure_ascii=False:保留中文等非 ASCII 字符,避免转成uXXXX编码;
indent=2:格式化输出,提升可读性;
- 需手动处理
datetime等非 JSON 原生类型(JSON 仅支持字符串 / 数字 / 布尔 / 列表 / 字典 /null)。
asdict(test_user):核心函数,将数据类实例递归转换为普通字典(嵌套的Address也会被转成字典);ensure_ascii=False:保留中文等非 ASCII 字符,避免转成uXXXX编码;indent=2:格式化输出,提升可读性;datetime等非 JSON 原生类型(JSON 仅支持字符串 / 数字 / 布尔 / 列表 / 字典 /null)。
如果有多个数据类需要转换,手动处理非基础类型会很繁琐,推荐自定义JSONEncoder,实现统一的序列化规则。
class DataclassJSONEncoder(json.JSONEncoder):
"""自定义JSON编码器,支持dataclass和常见非基础类型"""
def default(self, obj):
# 第一步:处理dataclass实例
if hasattr(obj, "__dataclass_fields__"): # 判断是否是dataclass
return asdict(obj)
# 第二步:处理datetime类型
if isinstance(obj, datetime):
return obj.isoformat()
# 第三步:其他类型交给父类处理(会抛出标准异常)
return super().default(obj)
# 直接使用自定义编码器序列化
user_json = json.dumps(
test_user,
cls=DataclassJSONEncoder, # 指定自定义编码器
ensure_ascii=False,
indent=2
)
print(user_json)
- 继承
json.JSONEncoder并重写default方法:这是json模块扩展序列化规则的标准方式;
__dataclass_fields__:dataclass 实例的内置属性,用于判断是否为数据类;
- 可扩展:如需支持
date/UUID等类型,只需在default方法中新增isinstance判断即可;
- 无需手动转字典,直接序列化数据类实例,代码更简洁。
json.JSONEncoder并重写default方法:这是json模块扩展序列化规则的标准方式;__dataclass_fields__:dataclass 实例的内置属性,用于判断是否为数据类;date/UUID等类型,只需在default方法中新增isinstance判断即可;
将转换逻辑封装成工具函数,一键调用,适合项目中多处使用的场景:
def dataclass_to_json(obj, indent=2):
"""
数据类转JSON字符串的工具函数
:param obj: 数据类实例(支持嵌套)
:param indent: 格式化缩进,None表示紧凑输出
:return: JSON字符串
"""
return json.dumps(
obj,
cls=DataclassJSONEncoder,
ensure_ascii=False,
indent=indent
)
# 调用示例(一行搞定)
user_json = dataclass_to_json(test_user)
print(user_json)
如果你的场景需要数据验证 + 优雅序列化,推荐直接使用pydantic(Python 生态中最主流的数据验证库),它的BaseModel比原生dataclass更强大,且原生支持 JSON 转换。
pip install pydantic
from pydantic import BaseModel
from datetime import datetime
# 替换原生dataclass为pydantic.BaseModel
class Address(BaseModel):
province: str
city: str
detail: str = ""
class User(BaseModel):
id: int
name: str
age: int
register_time: datetime
address: Address
tags: list[str] = None
# 可选:自定义JSON序列化配置(如datetime格式)
class Config:
json_encoders = {
datetime: lambda v: v.strftime("%Y-%m-%d %H:%M:%S") # 自定义时间格式
}
# 创建实例(pydantic会自动验证字段类型)
test_user = User(
id=1001,
name="张三",
age=28,
register_time=datetime(2026, 1, 19, 10, 30),
address=Address(province="浙江省", city="杭州市", detail="西湖区XX路"),
tags=["VIP", "新用户"]
)
# 原生支持JSON转换(一行搞定)
user_json = test_user.json(ensure_ascii=False, indent=2)
print(user_json)
{
"id": 1001,
"name": "张三",
"age": 28,
"register_time": "2026-01-19 10:30:00",
"address": {
"province": "浙江省",
"city": "杭州市",
"detail": "西湖区XX路"
},
"tags": ["VIP", "新用户"]
}
- 原生支持
json()方法:无需手动写编码器,开箱即用;
- 自动数据验证:创建实例时会校验字段类型(如
age传字符串会直接报错);
- 灵活配置:通过
Config.json_encoders自定义非基础类型的序列化规则;
- 支持嵌套、可选字段、默认值等,完全兼容原生 dataclass 的用法,且功能更强。
json()方法:无需手动写编码器,开箱即用;age传字符串会直接报错);Config.json_encoders自定义非基础类型的序列化规则;
- 简单场景:用
dataclasses.asdict + json.dumps,手动处理非基础类型,快速实现;
- 通用场景:自定义
JSONEncoder,统一管理序列化规则,适合多个数据类的项目;
- 生产环境:优先使用
pydantic.BaseModel,兼顾数据验证和优雅序列化,减少冗余代码;
- 核心原则:避免手动拼接字典,利用内置工具 / 成熟库实现转换,保证代码的可维护性和扩展性。
dataclasses.asdict + json.dumps,手动处理非基础类型,快速实现;JSONEncoder,统一管理序列化规则,适合多个数据类的项目;pydantic.BaseModel,兼顾数据验证和优雅序列化,减少冗余代码;以上就是Python数据类转换为JSON的常用方法总结的详细内容,更多关于Python数据类转JSON的资料请关注风君子博客其它相关文章!
您可能感兴趣的文章:
- 将Python数据类转换为JSON的三种方法
- 将Python数据类优雅地转换为JSON的方法详解
- Python中数据类转换为JSON的方法详解
- Python xml、字典、json、类四种数据类型如何实现互相转换