如何使用Python模块'attrs'实现"attr.asdict(MyObject)"的反向操作?

14
在Python模块attrs文档指出了一种将属性类转换为字典表示的方法: 示例:
>>> @attr.s
... class Coordinates(object):
...     x = attr.ib()
...     y = attr.ib()
...
>>> attr.asdict(Coordinates(x=1, y=2))
{'x': 1, 'y': 2}

如何实现相反的效果,即通过有效的字典表示来实例化Coordinates,而无需冗长的样板代码,并且能够享受attrs模块带来的乐趣?
3个回答

16

显然,只需在相应的 attrs 类初始化中使用字典解包 (双星号) 运算符即可。

示例:

>>> Coordinates(**{'x': 1, 'y': 2})
Coordinates(x=1, y=2)

21
只有当你的类是扁平的且没有嵌套的复杂类型时,这个方法才有效。 - Jonathan Nazario

11
作为一种更通用的解决方案,它可与 attrs 嵌套类、枚举或任何其他类型的注释结构一起使用。您可以使用https://github.com/Tinche/cattrs。它还通过定义结构/解构钩子来支持结构/非结构自定义。
示例:
import attr, cattr
   
@attr.s(slots=True, frozen=True)  # It works with normal classes too.
class C:
        a = attr.ib()
        b = attr.ib()
    
instance = C(1, 'a')
cattr.unstructure(instance)
# {'a': 1, 'b': 'a'}
cattr.structure({'a': 1, 'b': 'a'}, C)
# C(a=1, b='a')

3

我在我的Web应用程序中这样做,以便能够将其序列化/反序列化为JSON:

首先,我在我的类上创建了一个方法,返回一个更适合序列化的版本:

def asdict(self, serializable=True):
    if serializable:
        as_dict['type'] = self.__class__.__name__
        return as_dict
    else:
        return attr.asdict(self)

当我需要将这些字典(实际上是JSON对象)之一转换回类实例时:

obj_type = values.pop('type')
if obj_type in obj_list:
    obj = getattr(sys.modules[__name__], obj_type)(**values)

据我所知,您的解决方案需要一个额外的状态来携带类型名称?此外,当您说“我在我的类上创建了一个方法”时,您指的是哪些类并不清楚。无论如何,我只收到Python字典,我不能修改它们,但可以期望具体的键将其建模为简单的DTO以便于进一步使用。 - kuza
此外,@patrick-shechetin,您可以创建一个通用方法,从JSON字典动态创建attrs DTOs。更重要的是,如果您有它们的JSON模式,则不需要在有效负载本身中携带类型名称。只要您可以确保字典针对具体类型的模式进行验证即可。您可以在我的其他Q/A中了解更多关于_JSL_和_attrs_的信息。 - kuza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接