0

0

如何让自定义类在 dataclasses.asdict() 中正确序列化

聖光之護

聖光之護

发布时间:2026-01-14 09:52:25

|

745人浏览过

|

来源于php中文网

原创

如何让自定义类在 dataclasses.asdict() 中正确序列化

`dataclasses.asdict()` 在处理继承自 `list` 的自定义类时会因迭代器提前耗尽导致空列表,根本原因是 `__init__` 中直接消费了可迭代参数;修复方式是避免在调用 `super().__init__()` 前遍历或修改原始迭代器。

dataclasses.asdict() 是将数据类实例递归转换为嵌套字典的官方推荐工具,但它对容器类型的处理有明确假设:当遇到 list 或 tuple 实例时,它会通过 type(obj)(...) 构造新实例,并传入一个生成器表达式(_asdict_inner(v) for v in obj)来逐项序列化元素。这一机制依赖于对象能被多次迭代——而问题中的 CustomFloatList 在 __init__ 中直接遍历了传入的 args(可能为生成器、map 对象等一次性迭代器),导致后续 asdict 内部的 for v in obj 遍历时已无元素可取,最终构造出空列表。

? 问题复现与根源分析

以下代码清晰展示了问题本质:

UXbot
UXbot

AI产品设计工具

下载
from dataclasses import dataclass, asdict

class CustomFloatList(list):
    def __init__(self, args):
        # ❌ 危险:此处遍历 args 会耗尽迭代器(如 map、range、生成器)
        for i, arg in enumerate(args):
            assert isinstance(arg, float), f"Index {i} must be float, got {type(arg).__name__}"
        super().__init__(args)  # 此时 args 已空!

@dataclass
class Poc:
    x: CustomFloatList

p = Poc(x=CustomFloatList([1.0, 2.0]))  # 注意:直接传 list 也能触发问题(因 list(iter) 不耗尽,但其他类型会)
print(asdict(p))  # {'x': []} ← 错误结果!
⚠️ 关键点:asdict 内部调用 type(obj)(v for v in obj) 时,obj 若已被遍历过一次(如 for ... in args),则第二次遍历(for v in obj)返回空。

✅ 正确实现方案

方案一:预缓存为列表(推荐,语义清晰)

class CustomFloatList(list):
    def __init__(self, args):
        # ✅ 安全:先转为 list,再校验和初始化
        args_list = list(args)  # 缓存所有值,支持多次遍历
        for i, arg in enumerate(args_list):
            if not isinstance(arg, float):
                raise TypeError(f"Index {i} must be float, got {type(arg).__name__}")
        super().__init__(args_list)

方案二:初始化后再校验(更高效,适合大数据

class CustomFloatList(list):
    def __init__(self, args):
        # ✅ 先委托父类构造,再校验内容
        super().__init__(args)
        # 此时 self 已包含全部元素,可安全遍历
        for i, arg in enumerate(self):
            if not isinstance(arg, float):
                raise TypeError(f"Index {i} must be float, got {type(arg).__name__}")

✅ 两种方案均能确保 asdict(p) 正确输出 {'x': [1.0, 2.0]}。

? 验证示例

@dataclass
class Poc:
    x: CustomFloatList

p = Poc(x=CustomFloatList([3.14, 2.71]))
print(p)           # Poc(x=[3.14, 2.71])
print(asdict(p))   # {'x': [3.14, 2.71]} ← 正确!

? 补充建议

  • 避免在 __init__ 中消耗外部迭代器:这是 Python 容器子类的通用原则,不仅影响 asdict,还可能破坏 copy.copy()、json.dumps()(配合自定义 encoder)等场景。
  • 考虑使用 __post_init__(仅限 dataclass):若该类本身也是 @dataclass,可在 __post_init__ 中做类型校验,但本例中 CustomFloatList 是独立容器类,不适用。
  • 替代方案:使用 typing.Sequence + @dataclass(frozen=True) + 自定义 __post_init__:若约束逻辑复杂,可放弃继承 list,改用组合模式(如 dataclass 包含 list[float] 字段 + 校验逻辑),提升可测试性与可维护性。

总之,让自定义容器兼容 asdict 的核心是保证其可重复迭代性。优先采用“先构造、后校验”或“预缓存再校验”的策略,即可兼顾类型安全与序列化健壮性。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

451

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

546

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

326

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

81

2025.09.10

css中float用法
css中float用法

css中float属性允许元素脱离文档流并沿其父元素边缘排列,用于创建并排列、对齐文本图像、浮动菜单边栏和重叠元素。想了解更多float的相关内容,可以阅读本专题下面的文章。

593

2024.04.28

C++中int、float和double的区别
C++中int、float和double的区别

本专题整合了c++中int和double的区别,阅读专题下面的文章了解更多详细内容。

105

2025.10.23

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

77

2025.09.05

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

39

2025.11.16

Golang 测试体系与代码质量保障:工程级可靠性建设
Golang 测试体系与代码质量保障:工程级可靠性建设

Go语言测试体系与代码质量保障聚焦于构建工程级可靠性系统。本专题深入解析Go的测试工具链(如go test)、单元测试、集成测试及端到端测试实践,结合代码覆盖率分析、静态代码扫描(如go vet)和动态分析工具,建立全链路质量监控机制。通过自动化测试框架、持续集成(CI)流水线配置及代码审查规范,实现测试用例管理、缺陷追踪与质量门禁控制,确保代码健壮性与可维护性,为高可靠性工程系统提供质量保障。

48

2026.02.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.5万人学习

Django 教程
Django 教程

共28课时 | 4.7万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号