結論
BaseModelを継承したクラスのインスタンスを
- 辞書で得たければ、
model_dump()model_dump(...): -> dict[str, Any]- https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_dump
- JSON 形式の文字列で得たければ、
model_dump_json()model_dump_json(...): -> str- https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_dump_json
はじめに
七尾百合子さん、お誕生日 305日目 おめでとうございます! nikkieです。
Pydantic について Today(※最近) I Learned です
目次
辞書に変換するか、JSON 文字列に変換するか
model_dump()
https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_dump
Generate a dictionary representation of the model,
Serializing data - Python mode
https://docs.pydantic.dev/latest/concepts/serialization/#python-mode
When using the Python mode, Pydantic models (略) will be (recursively) converted to dictionaries.
This is achievable by using themodel_dump()method:
✍️Pydantic モデル(例:BaseModelを継承したクラス)は、model_dump()メソッドで再帰的に辞書に変換される
model_dump_json()
https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_dump_json
Generates a JSON representation of the model using Pydantic's
to_jsonmethod.
Serializing data - JSON mode
https://docs.pydantic.dev/latest/concepts/serialization/#json-mode
Pydantic allows data to be serialized directly to a JSON-encoded string, by trying its best to convert Python values to valid JSON data.
This is achievable by using themodel_dump_json()method:
model_dump()のmode引数
model_dump(
*,
mode: Literal["json", "python"] | str = "python",
# 省略
) -> dict[str, Any]
If mode is 'json', the output will only contain JSON serializable types.
If mode is 'python', the output may contain non-JSON-serializable Python objects.
mode引数を"json"と指定した時、JSON シリアライズ可能な型のみを含むmode引数を"python"と指定した時、JSON シリアライズできない Python オブジェクトを含むかもしれないmode引数のデフォルト値はこちら
例えば Enum の扱いが違いました。
ADK の EvalStatus という Enum で示します:https://github.com/google/adk-python/blob/v1.22.1/src/google/adk/evaluation/eval_metrics.py#L37-L40
class EvalStatus(Enum): PASSED = 1 FAILED = 2 NOT_EVALUATED = 3
mode="json"では、Enum は value に変換されています。
{'eval_case_results': [{'final_eval_status': 1}]}
mode="python"では、Enum はそのまま保持されます。
{'eval_case_results': [{'final_eval_status': <EvalStatus.PASSED: 1>}]}
経緯:adk-python に取り違えたバグがあったのです
※adk-python 1.22.0 で、私の PR とは別のコミットにより直っています
https://github.com/google/adk-python/commit/fc4e3d6f607032259e68e91bcb1ad0815a03164e
eval_set_result_json = eval_set_result.model_dump_json() with open(eval_set_result_file_path, "w", encoding="utf-8") as f: f.write(json.dumps(eval_set_result_json, indent=2))
model_dump_json()では JSON 形式の文字列を得るため、json.dumps()1で文字列リテラルを JSON にしてしまっています(=バグ2)
取り組んでみたところ、eval_set_result.model_dump(mode="json")とすることで、JSON シリアライズ可能な辞書を得ます。
この辞書をjson.dumps()すれば JSON 形式の文字列となりますね3
引数なくmodel_dump()したことで Enum の差でテストが落ち、mode引数を知るのにつながりました。
終わりに
Pydantic のBaseModelを継承したクラスは、辞書にしたければmodel_dump()、JSON 文字列にしたければmodel_dump_json()です。
model_dump()はmode引数で JSON シリアライズ可能な型のみとするかを指定できます(指定しないときは JSON シリアライズできない型も含みます)