119

3.7 の標準ライブラリは、データクラスを dict に再帰的に変換できます (ドキュメントの例)。

from dataclasses import dataclass, asdict
from typing import List

@dataclass
class Point:
     x: int
     y: int

@dataclass
class C:
     mylist: List[Point]

p = Point(10, 20)
assert asdict(p) == {'x': 10, 'y': 20}

c = C([Point(0, 0), Point(10, 4)])
tmp = {'mylist': [{'x': 0, 'y': 0}, {'x': 10, 'y': 4}]}
assert asdict(c) == tmp

ネストがあるときに辞書をデータクラスに戻す方法を探しています。C(**tmp)データクラスのフィールドが単純な型であり、それ自体がデータクラスではない場合にのみ機能するようなもの。[jsonpickle][1] についてはよく知っていますが、これには顕著なセキュリティ警告が付いています。


編集:

回答では、次のライブラリが提案されています。

  • デイサイト
  • mashumaro (私はしばらく使用していましたが、うまく機能しますが、すぐにトリッキーなコーナーケースに遭遇しました)
  • pydantic (非常にうまく機能し、ドキュメントが優れており、コーナーケースが少ない) [1]: https://jsonpickle.github.io/
4

14 に答える 14

0

これを解決するために複合パターンを使用することをお勧めします。主な利点は、このパターンにクラスを追加し続けて、同じように動作させることができることです。

from dataclasses import dataclass
from typing import List


@dataclass
class CompositeDict:
    def as_dict(self):
        retval = dict()
        for key, value in self.__dict__.items():
            if key in self.__dataclass_fields__.keys():
                if type(value) is list:
                    retval[key] = [item.as_dict() for item in value]
                else:
                    retval[key] = value
        return retval

@dataclass
class Point(CompositeDict):
    x: int
    y: int


@dataclass
class C(CompositeDict):
    mylist: List[Point]


c = C([Point(0, 0), Point(10, 4)])
tmp = {'mylist': [{'x': 0, 'y': 0}, {'x': 10, 'y': 4}]}
assert c.as_dict() == tmp

補足として、ネストされた辞書、タプルなどの他のケースを処理する CompositeDict クラス内でファクトリ パターンを使用できます。これにより、ボイラープレートが大幅に節約されます。

于 2020-02-15T00:18:27.693 に答える