2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

dataclass で独自の初期化をする

Last updated at Posted at 2022-02-12

環境

python3.10

web api のレスポンスを dataclass にマッピングしたい

web api のレスポンスがこんな感じだった場合

response = {
    'user_id': 'xxxx@example.com',
    'purchase_histories': [
        {
            'name': '鉛筆',
            'price': 120
        },
        {
            'name': '消しゴム',
            'price': 150
        }
    ]
}

次のような dataclass を2つ用意する。

from dataclasses import dataclass


@dataclass
class PurchaseHistory:
    name: str
    price: int


@dataclass
class Person:
    user_id: str
    purchase_histories: list[PurchaseHistory]

で、こんな感じで初期化する。

histories = [PurchaseHistory(name=history['name'], price=history['price']) for history in response['purchase_histories']]
p = Person(user_id=response['user_id'], purchase_histories=histories)

履歴の部分を取り出して先に PurchaseHistory の list を作って Person のコンストラクタに入れるって、使う側からすると使いにくい。

InitVar を使う

先ほどの Person クラスを以下のように変える。

@dataclass
class Person:
    user_id: str
    purchase_histories: list[PurchaseHistory] = field(init=False)
    histories: InitVar[list[dict]]

    def __post_init__(self, histories: dict):
        self.purchase_histories = [PurchaseHistory(name=history['name'], price=history['price']) for history in histories]

そうすると、呼び出し側はこんな感じで呼び出せる。

p = Person(user_id=response['user_id'], histories=response['purchase_histories'])

InitVar を使うと、コンストラクタと、 post_init メソッド内でしか使えない変数が使えるようになって、それを使って本来必要な purchase_histories を初期化できる。

2
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?