python 如何将字典转换为数据类
本文的主要目的是演示如何将嵌套字典转换为数据类。 介绍了三种不同类型的方法及其解释。
将字典转换回数据类
根据您正在进行的项目,您可能会遇到需要将字典转换回数据类的场景。 虽然这种情况可能很少见,但在某些情况下您可能需要进行转换,尤其是当您想要防止意外行为时。
这种情况的一个示例是转换后的字典是嵌套的或复杂的,例如具有复杂类型的成员或数据类的成员。
从数据类导入数据类,asdict
@dataclass
class A:
x: int
@dataclass
class B:
x: A
y: A
@dataclass
class C:
a: B
b: B
在上述情况下,数据类 C 在转换为字典时有时会造成转换问题。 问题的发生主要是由于类成员类型的处理失败。
要克服此解决方案,您可以根据自己的喜好和项目的性质选择多种方法。 如果您正在从事个人项目并且对数据性质的范围有很好的了解,那么使用简单的变通方法是安全的。
但是,在大规模数据的情况下,通常建议安全起见并使用第三方库(最好是开源的),因为它们是为在广泛的用例上运行而设计的。 因此,它允许他们处理更广泛的数据变体。
使用 post_init 将字典转换回数据类
最简单的方法之一是利用在初始化数据类后自动调用的 __post_init__
函数。
从数据类导入数据类,asdict
@dataclass
class SimpleDClazz:
m_one: str
m_two: str
@dataclass
class ComplexDClazz:
simpKlazz: SimpleDClazz
def __post_init__(self):
if isinstance(self.simpKlazz, dict):
self.simpKlazz = SimpleDClazz(**self.simpKlazz)
foo = ComplexDClazz(simpKlazz=SimpleDClazz(m_one="1", m_two="2"))
d= asdict(foo)
print(d)
o = ComplexDClazz(**d)
print(o)
输出:
{'simpKlazz': {'m_one': '1', 'm_two': '2'}}
ComplexDClazz(simpKlazz=SimpleDClazz(m_one='1', m_two='2'))
初始化数据类 ComplexDClazz 后调用 _post_init 函数。 由于这个独特的属性,我们可以使用它来帮助将字典转换回数据类。
所有必要的实现都在 __post_init_
函数中完成。 代码可以分为两个主要部分:
- 在函数的开始,判断传入的字典dict是否与我们成员simpKlazz的类型相同。
- 如果条件为真,则在将字典值转换为正确类型后更新成员变量 simpKlazz。
使用适宜性
尽管体积小且独立,但即使在对不同类型的数据类进行严格测试后,该解决方案仍能保持良好状态。 如果您正在寻找一个独立的小型解决方案,这个解决方案似乎是一个不错的选择,但您可能必须在您计划使用的每个数据类中实现这个功能。
如果您正在从事大型项目,请将您自己的测试用例应用到解决方案中,看看它是否适合您的用例。
使用自定义实现将字典转换回数据类
考虑以下用于将嵌套字典转换回数据类的函数。
import dataclasses as dc
from dataclasses import dataclass, asdict
def dict_to_dataklass(klass, d):
try:
fieldtypes = {f.name:f.type for f in dc.fields(klass)}
return klass(**{f:dict_to_dataklass(fieldtypes[f],d[f]) for f in d})
except:
return d # The object is not a dataclass field
@dataclass
class SimpleDClazz:
x: float
y: float
@dataclass
class ComplexDClazz:
a: SimpleDClazz
b: SimpleDClazz
line = ComplexDClazz(SimpleDClazz(1,2), SimpleDClazz(3,4))
assert line == dict_to_dataklass(ComplexDClazz, asdict(line))
print("Success")
输出:
Success
这个简单的五行代码包含一个 try-catch 块,其中完成了两件事:
- 假设 klass 是一个数据类。 提取数据类中的所有字段,它们的名称和类型更具体。
- 检索完所有字段后,将根据检索到的字段生成一个 klass 类型的数据类对象。 递归调用确保相应地处理和转换字段内的任何嵌套类。
- 当 try 块失败时(主要是当传递的参数不是所需的类型时),返回原始传递的对象。 这确保如果传递的对象不是合适的类型,它会被返回,作为递归调用的停止条件。
使用适宜性
此方法最适用于不同类型范围不大且大多数情况已知的小型项目。 对于规模较大的项目,这种方法在遇到 corner case 时可能会出乎意料地奏效。
建议使用数据类格式的测试用例对此进行测试,以根除任何潜在的错误。
使用 dacite(第三方库)将字典转换回数据类
dacite 是一个开源的第三方库,旨在简化 Python 中数据类的创建。 幸运的是,该库包含执行我们想要的功能的函数,从传递的字典(嵌套或非嵌套)创建数据类。
from dataclasses import dataclass
from dacite import from_dict
@dataclass
class DKlazz:
m_one: str
m_two: int
is_working: bool
sample = {
'm_one': '1',
'm_two': 2,
'is_working': False,
}
dk = from_dict(data_class=DKlazz, data=sample)
assert dk == DKlazz(m_one='1', m_two=2, is_working=False)
print("Success")
输出:
Success
dacite 仅包含一个函数,from_dict,它允许从给定的字典对象创建数据类。
使用该功能非常简单。 它由两个参数组成:数据类和字典。
然后该函数将给定的字典转换为给定类型的数据类对象并返回——所有这些都没有任何自定义函数的麻烦。
使用适宜性
开源的好处是万一遇到任何错误,会立即报告,并立即开始修复工作。 请记住,这种方法是全方位的,适用于小型和大型项目。
如果发现此类情况,可以将它们报告给 GitHub 存储库,开发人员或其他社区成员可以在其中帮助生成修复程序。 但是,如果您不想下载任何额外的第三方库,这个选项似乎不是最可行的。
相关文章
Django 中的 Slug
发布时间:2023/05/04 浏览次数:173 分类:Python
-
本篇文章旨在定义一个 slug 以及我们如何使用 slug 字段在 Python 中使用 Django 获得独特的帖子。
在 Django 中按降序过滤查询集中的项目
发布时间:2023/05/04 浏览次数:157 分类:Python
-
在这个讲解中,学习如何借助 Django 中的 order_by() 方法按降序过滤出查询集中的项目。
Django ALLOWED_HOSTS 介绍
发布时间:2023/05/04 浏览次数:181 分类:Python
-
本文展示了如何创建您的 Django 网站,为公开发布做好准备,如何设置 ALLOWED_HOSTS 以及如何在使用 Django 进行 Web 部署期间修复预期的主要问题。
Django 中的 Select_related 方法
发布时间:2023/05/04 浏览次数:129 分类:Python
-
本文介绍了什么是查询集,如何处理这些查询以及我们如何利用 select_related() 方法来过滤 Django 中相关模型的查询。
使用 Post 请求将数据发送到 Django 服务器
发布时间:2023/05/04 浏览次数:159 分类:Python
-
在这篇关于Django的讲解中,我们简要介绍了post和get请求以及如何在Django中用post实现CSRF token。
Django 返回 JSON
发布时间:2023/05/04 浏览次数:106 分类:Python
-
在与我们的讨论中,我们简要介绍了 JSON 格式,并讨论了如何借助 Django 中的 JsonResponse 类将数据返回为 JSON 格式。
在 Django 中创建对象
发布时间:2023/05/04 浏览次数:59 分类:Python
-
本文的目的是解释什么是模型以及如何使用 create() 方法创建对象,并了解如何在 Django 中使用 save() 方法。
在 Django 中为多项选择创建字段
发布时间:2023/05/04 浏览次数:75 分类:Python
-
在本文中,我们将着眼于为多项选择创建一个字段,并向您展示如何允许用户在 Django 中进行多项选择。