首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >用dacite.from_dict动态添加数据集字段

用dacite.from_dict动态添加数据集字段
EN

Stack Overflow用户
提问于 2022-03-03 09:18:04
回答 1查看 1.3K关注 0票数 0

我正在使用dacite将Python字典转换为dataclass。是否有一种方法可以动态地将字段添加到数据集中?与下面的示例一样,dataclass“参数”只定义了一个timeseries "timeseriesA",但可能还有其他的(通过字典提供)不能声明的。

代码语言:javascript
运行
复制
from dataclasses import asdict, dataclass
from typing import Dict, List, Optional

from dacite import from_dict

@dataclass(frozen = True)
class TimeSeries:
  name: str
  unit: str
  data: Optional[List[float]]
  
@dataclass(frozen = True)
class Parameters:
  timeseriesA: TimeSeries
  
@dataclass(frozen = True)
class Data:
  parameters: Parameters
  
  @classmethod
  def fromDict(cls, data: Dict) -> 'Data':
    return from_dict(cls, data)

  @classmethod
  def toDict(cls) -> Dict:
    return asdict(cls)

  
def main() -> None:

  d: Dict = {
    'parameters': {
      'timeseriesA': {
        'name': 'nameA',
        'unit': 'USD',
        'data': [10, 20, 30, 40]
      },
      'timeseriesB': {
        'name': 'nameB',
        'unit': 'EUR',
        'data': [60, 30, 40, 50]
      }
    }
  }

  data: Data = Data.fromDict(d)

if __name__ == '__main__':
  main()

在本例中,dacite将忽略"timeseriesB“,但应将其作为”参数“数据集的字段添加。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-03-04 05:21:28

通常,在定义了类之后,动态地将字段添加到dataclass并不是一个好的实践。但是,由于源dict对象中字段的动态性质,这为在数据集中使用dict提供了一个很好的用例。

下面是一个使用dict字段处理源对象中键的动态映射的简单示例,它使用dataclass-wizard,它也是一个类似的JSON序列化库。下面概述的方法处理dict对象中的无关数据,例如timeseriesB

代码语言:javascript
运行
复制
from __future__ import annotations

from dataclasses import dataclass
from dataclass_wizard import JSONWizard


@dataclass(frozen=True)
class Data(JSONWizard):
    parameters: dict[str, TimeSeries]


@dataclass(frozen=True)
class TimeSeries:
    name: str
    unit: str
    data: list[float] | None


data: dict = {
    'parameters': {
        'timeseriesA': {
            'name': 'nameA',
            'unit': 'USD',
            'data': [10, 20, 30, 40]
        },
        'timeseriesB': {
            'name': 'nameB',
            'unit': 'EUR',
            'data': [60, 30, 40, 50]
        }
    }
}


def main():
    # deserialize from dict
    d = Data.from_dict(data)
    print(d.parameters['timeseriesB'].unit)  # EUR

    print(repr(d)) 
    # Data(parameters={'timeseriesA': TimeSeries(name='nameA', unit='USD', data=[10.0, 20.0, 30.0, 40.0]),
    #                  'timeseriesB': TimeSeries(name='nameB', unit='EUR', data=[60.0, 30.0, 40.0, 50.0])})


if __name__ == '__main__':
    main()

诚然,dataclass-wizard并不像dacite那样执行严格的类型检查,而是在可能的情况下执行隐式类型强制,如str到带注释的int。也许结果是,它的整体速度要快得多;另一个好的方面是序列化比内置的dataclasses.asdict还要快一些:-)

以下是一些快速测试:

代码语言:javascript
运行
复制
from dataclasses import asdict, dataclass
from typing import Dict, List, Optional

from dacite import from_dict
from dataclass_wizard import JSONWizard
from timeit import timeit


@dataclass(frozen=True)
class TimeSeries:
    name: str
    unit: str
    data: Optional[List[float]]


@dataclass(frozen=True)
class Parameters:
    timeseriesA: TimeSeries


@dataclass(frozen=True)
class Data:
    parameters: Parameters

    @classmethod
    def fromDict(cls, data: Dict) -> 'Data':
        return from_dict(cls, data)

    def toDict(self) -> Dict:
        return asdict(self)


@dataclass(frozen=True)
class ParametersWizard:
    # renamed because default key transform is `camelCase` -> `snake_case`
    timeseries_a: TimeSeries


@dataclass(frozen=True)
class DataWizard(JSONWizard):
    # enable debug mode in case of incorrect types etc.
    class _(JSONWizard.Meta):
        debug_enabled = True

    parameters: ParametersWizard


data: Dict = {
    'parameters': {
        'timeseriesA': {
            'name': 'nameA',
            'unit': 'USD',
            'data': [10, 20, 30, 40]
        },
        'timeseriesB': {
            'name': 'nameB',
            'unit': 'EUR',
            'data': [60, 30, 40, 50]
        }
    }
}


def main():
    n = 10_000

    print(f"From Dict:        {timeit('Data.fromDict(data)', globals=globals(), number=n):.3f}")
    print(f"From Dict (Wiz):  {timeit('DataWizard.from_dict(data)', globals=globals(), number=n):.3f}")

    data_1: Data = Data.fromDict(data)
    data_wiz: Data = DataWizard.from_dict(data)

    g = globals().copy()
    g.update(locals())

    print(f"To Dict:        {timeit('data_1.toDict()', globals=g, number=n):.3f}")
    print(f"To Dict (Wiz):  {timeit('data_wiz.to_dict()', globals=g, number=n):.3f}")


if __name__ == '__main__':
    main()

结果,在我的电脑(Windows)上:

代码语言:javascript
运行
复制
From Dict:        1.663
From Dict (Wiz):  0.059
To Dict:        0.105
To Dict (Wiz):  0.057
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71334683

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档