Dict からの Python データ クラス

Salman Mehmood 2023年6月21日
  1. ディクショナリをデータ クラスに戻す
  2. __post_init__ を使用して辞書をデータ クラスに戻す
  3. カスタム実装を使用してディクショナリをデータ クラスに戻す
  4. dacite を使用してディクショナリをデータ クラスに戻す (サード パーティ ライブラリ)
Dict からの Python データ クラス

この記事の主な目的は、ネストされたディクショナリをデータ クラスに変換する方法を示すことです。 3つの異なるタイプのアプローチが、その説明とともに提示されます。

ディクショナリをデータ クラスに戻す

作業しているプロジェクトによっては、ディクショナリをデータ クラスに戻す必要があるシナリオが発生する場合があります。 まれなケースかもしれませんが、特に予期しない動作を防ぎたい場合に、変換を行う必要がある特定の状況があります。

このようなシナリオの例としては、変換されたディクショナリが入れ子になっている、または複雑である場合があります。たとえば、複雑な型のメンバーやデータ クラスのメンバーが含まれている場合などです。

from dataclasses import dataclass, asdict


@dataclass
class A:
    x: int


@dataclass
class B:
    x: A
    y: A


@dataclass
class C:
    a: B
    b: B

上記の場合、データ クラス C は辞書に変換されるときに変換の問題を引き起こすことがあります。 この問題は、主にクラス メンバーの型の処理に失敗したために発生します。

この解決策を克服するために、好みとプロジェクトの性質に基づいていくつかのアプローチを選択できます。 データの性質の範囲をよく理解している個人的なプロジェクトに取り組んでいる場合は、簡単な回避策を使用しても安全です。

ただし、大規模なデータの場合は、サードパーティのライブラリ (できればオープンソース) を安全に使用することをお勧めします。これらのライブラリは幅広いユースケースで動作するように設計されているためです。 したがって、より広い範囲のデータバリアントを処理できます。

__post_init__ を使用して辞書をデータ クラスに戻す

最も簡単な方法の 1つは、データ クラスの初期化後に自動的に呼び出される __post_init__ 関数を利用することです。

from dataclasses import dataclass, asdict


@dataclass
class SimpleDClazz:
    m_one: str
    m_two: str


@dataclass
class ComplexDClazz:
    simpKlazz: SimpleDClazz

    def __post_init__(self):
        if isinstance(self.simpKlazz, dict):
            self.simpKlazz = SimpleDClazz(**self.simpKlazz)


foo = ComplexDClazz(simpKlazz=SimpleDClazz(m_one="1", m_two="2"))

d = asdict(foo)
print(d)
o = ComplexDClazz(**d)
print(o)

出力:

{'simpKlazz': {'m_one': '1', 'm_two': '2'}}
ComplexDClazz(simpKlazz=SimpleDClazz(m_one='1', m_two='2'))

データクラス ComplexDClazz が初期化されると、__post_init_ 関数が呼び出されます。 この一意のプロパティにより、これを使用して辞書をデータ クラスに戻すことができます。

必要なすべての実装は、__post_init_ 関数内で行われます。 コードは、次の 2つの主要部分に分けることができます。

  1. 関数の開始時に、渡された辞書 dict がメンバー simpKlazz の型と同じ型であるかどうかが判断されます。
  2. 条件が真の場合、辞書の値を正しい型に変換した後、メンバー変数 simpKlazz が更新されます。

使用適性

小さくて独立していますが、さまざまなタイプのデータ クラスを使用した厳密なテストの後でも、ソリューションは十分に保持されます。 独立した小規模なソリューションを探している場合、このソリューションは良い選択のように思えますが、使用する予定のすべてのデータ クラスにこの関数を実装する必要がある場合があります。

大規模なプロジェクトに取り組んでいる場合は、独自のテスト ケースをソリューションに適用して、ユース ケースにどの程度適しているかを確認してください。

カスタム実装を使用してディクショナリをデータ クラスに戻す

入れ子になったディクショナリをデータ クラスに戻す次の関数を検討してください。

import dataclasses as dc
from dataclasses import dataclass, asdict


def dict_to_dataklass(klass, d):
    try:
        fieldtypes = {f.name: f.type for f in dc.fields(klass)}
        return klass(**{f: dict_to_dataklass(fieldtypes[f], d[f]) for f in d})
    except:
        return d  # The object is not a dataclass field


@dataclass
class SimpleDClazz:
    x: float
    y: float


@dataclass
class ComplexDClazz:
    a: SimpleDClazz
    b: SimpleDClazz


line = ComplexDClazz(SimpleDClazz(1, 2), SimpleDClazz(3, 4))
assert line == dict_to_dataklass(ComplexDClazz, asdict(line))
print("Success")

出力:

Success

この単純な 5 行のコードは try-catch ブロックで構成されており、そこで 2つのことが行われます。

  1. klass がデータ クラスであると仮定します。 データ クラスのすべてのフィールドが抽出され、それらの名前と型がより具体的になります。
  2. すべてのフィールドが取得された後、取得されたフィールドから klass 型のデータ クラス オブジェクトが生成されます。 再帰呼び出しにより、フィールド内のネストされたクラスが処理され、それに応じて変換されます。
  3. try ブロックが失敗した場合 (ほとんどの場合、渡されたパラメーターが必要な型でない場合)、元の渡されたオブジェクトが返されます。 これにより、渡されたオブジェクトが適切なタイプでない場合に返され、再帰呼び出しの停止条件として機能します。

使用適性

この方法は、さまざまなタイプのスコープが大きくなく、ほとんどのケースが既知である小規模なプロジェクトに最適です。 大規模なプロジェクトでは、まれなケースに遭遇したときに、この方法が予期せず機能することがあります。

潜在的なエラーを根絶するために、データ クラス形式のテスト ケースでこれをテストすることをお勧めします。

dacite を使用してディクショナリをデータ クラスに戻す (サード パーティ ライブラリ)

daciteは、Python でのデータ クラスの作成を簡素化することを目的としたオープンソースのサードパーティ ライブラリです。 幸いなことに、ライブラリは、渡された辞書 (ネストされているかどうかに関係なく) からデータ クラスを作成する、私たちが望むことを行う関数で構成されています。

from dataclasses import dataclass
from dacite import from_dict


@dataclass
class DKlazz:
    m_one: str
    m_two: int
    is_working: bool


sample = {
    "m_one": "1",
    "m_two": 2,
    "is_working": False,
}

dk = from_dict(data_class=DKlazz, data=sample)

assert dk == DKlazz(m_one="1", m_two=2, is_working=False)
print("Success")

出力:

Success

dacite は、与えられたディクショナリ オブジェクトからデータ クラスを作成できる、from_dict という 1つの関数のみで構成されます。

関数の使用はかなり簡単です。 これは、データ クラスとディクショナリの 2つのパラメータで構成されます。

この関数は、指定された辞書を指定された型のデータ クラス オブジェクトに変換し、それを返します。カスタム関数の手間は一切かかりません。

使用適性

オープンソースの良いところは、エラーが発生した場合にすぐに報告され、修正作業がすぐに開始されることです。 このことを念頭に置いて、このアプローチは万能であり、小規模プロジェクトと大規模プロジェクトの両方で機能します。

そのようなケースが見つかった場合は、開発者または他のコミュニティ メンバーが修正の生成を支援できる GitHub リポジトリに報告できます。 ただし、追加のサードパーティ製ライブラリをダウンロードしたくない場合、このオプションは最も実行可能とは思えない場合があります。

著者: Salman Mehmood
Salman Mehmood avatar Salman Mehmood avatar

Hello! I am Salman Bin Mehmood(Baum), a software developer and I help organizations, address complex problems. My expertise lies within back-end, data science and machine learning. I am a lifelong learner, currently working on metaverse, and enrolled in a course building an AI application with python. I love solving problems and developing bug-free software for people. I write content related to python and hot Technologies.

LinkedIn

関連記事 - Python Dictionary

関連記事 - Python Dataclass