您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

在Python中创建嵌套的数据类对象

在Python中创建嵌套的数据类对象

这是一个具有与dataclasses模块本身的复杂度相匹配的复杂度的请求:这意味着,实现此“嵌套字段”功能的最佳方法可能是定义一个类似于的新装饰器@dataclass

值得一提的是,如果不需要该__init__方法的签名来反映字段及其认值,例如通过调用渲染的类dataclass,则可以简单得多:类装饰器将调用原始装饰器dataclass 并为其包装一些功能生成__init__方法可以使用简单的...(*args, **kwargs):样式功能来实现。

换句话说,要做的就是对生成__init__方法进行包装,该方法将检查在“ kwargs”中传递的参数,检查是否有任何对应于“数据类字段类型”的参数,如果是,则在调用之前生成嵌套对象原来的__init__。也许用英语比用Python拼写更难:

from dataclasses import dataclass, is_dataclass

def nested_dataclass(*args, **kwargs):
    def wrapper(cls):
        cls = dataclass(cls, **kwargs)
        original_init = cls.__init__
        def __init__(self, *args, **kwargs):
            for name, value in kwargs.items():
                field_type = cls.__annotations__.get(name, None)
                if is_dataclass(field_type) and isinstance(value, dict):
                     new_obj = field_type(**value)
                     kwargs[name] = new_obj
            original_init(self, *args, **kwargs)
        cls.__init__ = __init__
        return cls
    return wrapper(args[0]) if args else wrapper

请注意,除了不必担心__init__签名之外,这还忽略了传递init=False-因为无论如何它都是毫无意义的。

if返回行中的负责此工作,可以使用命名参数调用它,也可以像dataclass本身一样直接作为装饰器)

并在交互式提示上:

In [85]: @dataclass
    ...: class A:
    ...:     b: int = 0
    ...:     c: str = ""
    ...:

In [86]: @dataclass
    ...: class A:
    ...:     one: int = 0
    ...:     two: str = ""
    ...:     
    ...:

In [87]: @nested_dataclass
    ...: class B:
    ...:     three: A
    ...:     four: str
    ...:

In [88]: @nested_dataclass
    ...: class C:
    ...:     five: B
    ...:     six: str
    ...:     
    ...:

In [89]: obj = C(five={"three":{"one": 23, "two":"narf"}, "four": "zort"}, six="fnord")

In [90]: obj.five.three.two
Out[90]: 'narf'

如果您希望保留签名,我建议使用dataclasses模块本身中的私有帮助器函数来创建一个新的__init__

python 2022/1/1 18:38:04 有492人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶