はじめに
PrayForKyoani、nikkieです。
久しぶりの『ロバストPython』読書ログ。
将来の開発者に意図を伝えるPythonの書き方が指南された(議論のための)本です。
Pydanticの関係1で14章を読みました。
目次
前回の『ロバストPython』!
発売当初、いくつか読書ログを書きました。
- 『ロバストPython』読み始めました 📘「あなたの書くPython、将来の開発者に意図、伝えていますか?」 私(Python歴5年)「すいませんでしたあああ!🙇♂️ やり方マジで教えてください」 - nikkie-ftnextの日記
- 読書ログ | 『ロバストPython』5章「コレクション型」を読んで、コレクション(listやdictなどなど)への型ヒントの書き方や、振る舞いの拡張の仕方を完全に理解しました - nikkie-ftnextの日記
- 読書ログ | 『ロバストPython』10章「クラス」、不変式を維持せよ!と声高に叫ぶ章(議論する前の理解のまとめ) - nikkie-ftnextの日記
議論のための本なだけあって、各章で語りたいことが見つかり、読書会形式でPython使いと色々語れたらいいな〜と毎回感じます(どなたか🙏)
14章 pydanticによる実行時型チェック
監訳のHayaoさんによる書籍紹介スライド
読んだ後の感想ツイート
『ロバストPython』14章、Pydanticなんて便利なんだhttps://t.co/s4LECPYPtn
— nikkie にっきー (@ftnext) 2023年7月17日
pydanticのdataclassデコレータを紹介。
データクラス同様に型アノテーションで未来の開発者に意図が伝わり、その上ユーザが入力するデータ(不正かも)に対して実行時の検証までついてくる。
デコレータだけなのにここまで
実行時型チェック
『ロバストPython』では、将来の開発者に意図を伝えるために、型の重要さが説かれます。
型ヒントを書いて型チェッカを実行するという話が分量としては多いのですが、14章で扱うのは実行時の話。
例えばユーザ入力は不正なデータとなる可能性があります。
不正なデータで処理が進むよりは読み込んだ時点で例外を送出して落ちるのが望ましいですよね。
14章のサンプルコードはレストラン。
レストランで働く従業員や、提供する料理のメニューも扱っている、battery includedなデータです。
以下のようなYAMLファイルで表現されます。
https://github.com/pviafore/RobustPython/blob/dafb95d801dff2c8ff7856ba46d3c052d54e0033/code_examples/chapter14/restaurant.yaml
TypedDictの場合
TypedDictを使ってRestaurantが定義されます。
class Restaurant(TypedDict): ...
YAMLファイルを読み込むメソッドを以下のようにアノテーションします。
https://github.com/pviafore/RobustPython/blob/dafb95d801dff2c8ff7856ba46d3c052d54e0033/code_examples/chapter14/read_restaurant.py
def load_restaurant(filename: str) -> Restaurant: with open(filename) as yaml_file: return yaml.safe_load(yaml_file)
Restaurantとして不正なデータのYAMLは以下
- 属性の欠落 https://github.com/pviafore/RobustPython/blob/dafb95d801dff2c8ff7856ba46d3c052d54e0033/code_examples/chapter14/missing.yaml
- 属性の型の誤り https://github.com/pviafore/RobustPython/blob/dafb95d801dff2c8ff7856ba46d3c052d54e0033/code_examples/chapter14/wrong_type.yaml
これらの不正なRestaurantデータ、YAMLとしては壊れておらず読めちゃうので、実行時はload_restaurant
はRestaurant
型の値(すなわち辞書)を返します。
ところが後続の処理中に不備が顕在化し、そこで落ちます。
Pydanticが提供する実行時型チェックによる解決
上記の事象はPydanticによって解決されます。
サンプルコード:https://github.com/pviafore/RobustPython/blob/dafb95d801dff2c8ff7856ba46d3c052d54e0033/code_examples/chapter14/restaurant_pydantic.py
@pydantic.dataclasses.dataclass
2を使ってデータクラスをデコレート(9章の標準ライブラリのdataclassデコレータから、Pydanticのデコレータへ変えるだけ)。
たったこれだけで実行時型チェックが付加されます!
from pydantic.dataclasses import dataclass @dataclass class Restaurant: ...
読み込むメソッドはRestaurantクラスのインスタンスを初期化して返すように実装されます
def load_restaurant(filename: str) -> Restaurant: with open(filename) as yaml_file: data = yaml.safe_load(yaml_file) return Restaurant(**data)
不正なデータを渡すと、TypedDictの時と異なり、Pydanticによる検証でValidationErrorが送出されます。
不正なデータを使って処理が進むことはなく、load_restaurant
で処理が落ちます3。
指南された実行時型チェック
検証について教わりました。
- constr(制約付きの文字列)
- X文字以上、Y文字以下、この正規表現パターンの文字列など
- https://docs.pydantic.dev/1.10/usage/types/#arguments-to-constr
- conlist(制約付きのリスト)
- validatorデコレータ
- 属性についてカスタマイズしたバリデーションを実装できる
- https://docs.pydantic.dev/1.10/usage/validators/
頻出の制約はconstrやconlistで実装でき、カスタマイズした制約はデコレータを使って自由に実装できるという理解です。
写経コードはこちら:
終わりに
『ロバストPython』14章「pydanticによる実行時型チェック」の読書ログでした。
- 型チェックの隙間を埋める実行時型チェック
@dataclasses.dataclass
を@pydantic.dataclasses.dataclass
に変えるだけで導入可能- 標準ライブラリのデータクラスと同様の書き方なのに、実行時のチェックが提供される!便利すぎ
- Pydanticの各種バリデータを使ってバリデーションロジックを作り込める
- 10章で強調された不変式!
データクラスに不変式が絡んだり(クラスとの間隙を埋めるという言い回し)、Pydanticはパースライブラリ(出力を保証する)だったり、興味深いポイント目白押しでした。
こんなに便利なPydantic、使う機会を増やして経験値を積んでいきたいですね。