16

我正在编写一个库来访问 REST API。它返回带有用户对象的 json。我将其转换为 dict,然后将其转换为数据类对象。问题是并非所有字段都是固定的。我想动态添加其他字段(未在我的数据类中指定)。我可以简单地为我的对象分配值,但它们不会出现在对象表示中,并且dataclasses.asdict函数不会将它们添加到结果字典中:

from dataclasses import asdict, dataclass

@dataclass
class X:
    i: int

x = X(i=42)
x.s = 'text'

x
# X(i=42)

x.s
# 'text'

asdict(x)
# {'i': 42}
4

2 回答 2

20

您可以使用make_dataclass动态创建X

X = make_dataclass('X', [('i', int), ('s', str)])
x = X(i=42, s='text')

asdict(x)
# {'i': 42, 's': 'text'}

或作为派生类:

@dataclass
class X:
    i: int

x = X(i=42)
x.__class__ = make_dataclass('Y', fields=[('s', str)], bases=(X,))
x.s = 'text'

asdict(x)
# {'i': 42, 's': 'text'}
于 2018-09-27T12:03:04.250 回答
4

如前所述,标记为可选的字段应该可以解决问题。如果没有,请考虑使用dataclasses. 是的,常规属性应该可以很好地工作——尽管您必须在 中声明字段__post_init__,这有点不方便。

如果您想为属性设置默认值以便在创建对象后立即访问 getter 可以正常工作,并且如果您还希望能够通过构造函数设置默认值,则可以使用称为字段属性的概念;像dataclass-wizard这样的几个库为此提供了全面支持。

示例用法:

from dataclasses import asdict, dataclass
from typing import Optional

from dataclass_wizard import property_wizard


@dataclass
class X(metaclass=property_wizard):
    i: int
    s: Optional[str] = None

    @property
    def _s(self):
        return self._s

    @_s.setter
    def _s(self, s: str):
        self._s = s


x = X(i=42)
x.s = 'text'

x
# X(i=42, s='text')


x.s
# 'text'

asdict(x)
# {'i': 42, 's': 'text'}

免责声明:我是这个库的创建者(和维护者)。

于 2021-08-30T16:12:48.563 回答