0

0

attrs 与 cattrs:优雅处理嵌套数据结构的教程

霞舞

霞舞

发布时间:2025-08-05 23:02:25

|

223人浏览过

|

来源于php中文网

原创

attrs 与 cattrs:优雅处理嵌套数据结构的教程

本教程详细阐述了如何使用 Python 的 attrs 和 cattrs 库来高效处理嵌套的数据结构,特别是将包含字典列表的复杂数据转换为 attrs 定义的类实例列表。文章将解释 attrs 内置转换器的局限性,并演示 cattrs 如何通过其强大的结构化功能,自动且优雅地完成从原始字典数据到复杂 attrs 对象的映射,从而简化代码并提高可维护性。

理解 attrs 中的数据建模

python 中,attrs 库提供了一种简洁而强大的方式来定义结构化数据类,它通过装饰器和类型提示极大地简化了样板代码。当我们需要将外部数据(如 json 或字典)映射到这些定义好的 attrs 类时,通常会遇到嵌套结构的处理问题。

考虑一个场景,我们有一组角色数据,每个角色包含姓名信息,并且这些角色共同构成一个团队。数据结构如下所示:

data_source = {
    "characters": [
        {"first_name": "Duffy", "last_name": "Duck"},
        {"first_name": "Bugs", "last_name": "Bunny"},
        # ... 更多角色
    ]
}

我们希望将其转换为 attrs 类实例:

from attrs import define, field
from typing import List

@define(kw_only=True)
class Character:
    first_name: str
    last_name: str

@define
class LooneyToons:
    characters: List[Character] = field(factory=list) # 初始定义,稍后解释为何移除converter

attrs 内置转换器的局限性

attrs 提供了 converter 参数,用于在字段赋值时对输入值进行转换。例如,some_field: int = field(converter=int) 可以确保输入值被转换为整数。然而,当处理列表中的复杂对象转换时,直接使用 converter=Character 会遇到问题:

# 错误示例:直接将 Character 作为 List[Character] 的 converter
@define
class LooneyToons_Problematic:
    characters: List[Character] = field(factory=list, converter=Character)

# 尝试使用:
# LooneyToons_Problematic(characters=data_source['characters'])
# 这将导致 TypeError: Character.__init__() takes 1 positional argument but 2 were given

这个错误的原因是,attrs 的 converter 期望一个函数,该函数接收单个值并将其转换为目标类型。当我们将其应用于一个 List[Character] 字段时,attrs 会尝试将整个列表 data_source['characters'] 作为参数传递给 Character 类的构造函数(即 Character.__init__),这显然是不正确的,因为 Character 期望的是 first_name 和 last_name 这样的关键字参数,而不是一个字典列表。

手动转换与其不足

一种可行的解决方案是手动遍历列表,并为每个字典创建 Character 实例:

# 手动转换示例
looney_tunes_instance = LooneyToons(
    characters=[Character(**x) for x in data_source['characters']]
)
print(looney_tunes_instance)
# 输出: LooneyToons(characters=[Character(first_name='Duffy', last_name='Duck'), ...])

这种方法虽然有效,但在以下情况下显得不够优雅或高效:

  • 样板代码重复: 每次需要转换列表时,都需要编写类似的列表推导式。
  • 可读性下降: 随着数据结构的复杂性增加,手动转换逻辑会变得冗长且难以维护。
  • 不自动化: 无法在 LooneyToons 类的实例化过程中自动完成,需要外部手动处理。

引入 cattrs:自动化复杂数据结构转换

为了更优雅、自动化地处理 attrs 类与复杂嵌套数据(如字典、列表)之间的转换,cattrs 库应运而生。cattrs 是一个强大的工具,专门用于在 Python 对象和原始数据类型之间进行结构化(structuring)和非结构化(unstructuring)。它通过利用类型提示,能够智能地解析复杂的数据结构并自动执行深层转换。

Miniflow
Miniflow

AI工作流自动化平台

下载

使用 cattrs 解决上述问题非常简单:

  1. 移除 converter 参数: 在 LooneyToons 类的 characters 字段定义中,我们不再需要 converter 参数。cattrs 将根据类型提示 List[Character] 自动推断出正确的转换逻辑。

  2. 使用 cattrs.structure: 调用 cattrs.structure() 函数,将原始字典数据和目标 attrs 类作为参数传入。

以下是完整的 cattrs 解决方案代码:

from typing import List
from attrs import define, field
from cattrs import structure # 导入 cattrs 的 structure 函数

# 示例数据
data_source = {
    "characters": [
        {"first_name": "Duffy", "last_name": "Duck"},
        {"first_name": "Bugs", "last_name": "Bunny"},
        {"first_name": "Sylvester", "last_name": "Pussycat"},
        {"first_name": "Elmar", "last_name": "Fudd"},
        {"first_name": "Tweety", "last_name": "Bird"},
        {"first_name": "Sam", "last_name": "Yosemite"},
        {"first_name": "Wile E.", "last_name": "Coyote"},
        {"first_name": "Road", "last_name": "Runner"},
    ]
}

# 定义内部的 Character 类
@define(kw_only=True)
class Character:
    first_name: str
    last_name: str

# 定义外部的 LooneyToons 类,注意移除了 converter 参数
@define
class LooneyToons:
    characters: List[Character] = field(factory=list)

# 使用 cattrs.structure 进行转换
looney_tunes_instance = structure(data_source, LooneyToons)

print(looney_tunes_instance)
# 预期输出:
# LooneyToons(characters=[Character(first_name='Duffy', last_name='Duck'), Character(first_name='Bugs', last_name='Bunny'), Character(first_name='Sylvester', last_name='Pussycat'), Character(first_name='Elmar', last_name='Fudd'), Character(first_name='Tweety', last_name='Bird'), Character(first_name='Sam', last_name='Yosemite'), Character(first_name='Wile E.', last_name='Coyote'), Character(first_name='Road', last_name='Runner')])

# 验证类型
print(isinstance(looney_tunes_instance.characters[0], Character)) # True

在这个例子中,cattrs.structure(data_source, LooneyToons) 会执行以下操作:

  1. 它检查 LooneyToons 的类型提示。
  2. 发现 characters 字段被标注为 List[Character]。
  3. cattrs 遍历 data_source['characters'] 中的每个字典。
  4. 对于每个字典,cattrs 知道它需要将其转换为一个 Character 实例,因此它会自动调用 Character(**dict_item) 来创建对象。
  5. 最终,所有创建的 Character 实例被收集到一个列表中,并赋值给 looney_tunes_instance.characters。

总结与注意事项

  • attrs 的 converter vs. cattrs.structure: attrs 内置的 converter 适用于简单的、单值到单值的转换。当需要处理嵌套对象、列表或更复杂的类型映射时,cattrs 是更专业、更强大的选择。
  • 类型提示的重要性: cattrs 严重依赖于 Python 的类型提示来理解如何进行数据结构化。确保你的 attrs 类字段都带有准确的类型提示。
  • 灵活性与扩展性: cattrs 提供了注册自定义转换器(register_structure_hook)的能力,这使得它能够处理各种非标准的数据类型或特殊的转换逻辑,进一步增强了其灵活性。
  • 减少样板代码: 通过使用 cattrs,你可以将数据转换的复杂逻辑从业务代码中解耦,使得 attrs 类的定义更加纯粹,只关注数据结构本身。

通过结合 attrs 定义清晰的数据模型和 cattrs 自动化数据映射,开发者可以更高效、更优雅地处理 Python 中的复杂数据结构,显著提高代码的可读性、可维护性和健壮性。

相关专题

更多
python开发工具
python开发工具

php中文网为大家提供各种python开发工具,好的开发工具,可帮助开发者攻克编程学习中的基础障碍,理解每一行源代码在程序执行时在计算机中的过程。php中文网还为大家带来python相关课程以及相关文章等内容,供大家免费下载使用。

778

2023.06.15

python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

684

2023.07.20

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

768

2023.07.25

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

739

2023.07.31

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

1445

2023.08.03

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

571

2023.08.04

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

579

2023.08.04

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

751

2023.08.11

c++ 根号
c++ 根号

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

58

2026.01.23

热门下载

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

精品课程

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

共4课时 | 19.4万人学习

Django 教程
Django 教程

共28课时 | 3.5万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.2万人学习

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

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