Pythonスキーマバリデーションライブラリ比較 (pydantic, marshmallow, attrs, cerberus)
- Authors
- @__Attsun__
- Published on
ウェブ API の作成など、外部からやってくるデータを安全に捌く上で、スキーマ定義とバリデーションは非常に重要です。
また、特に Python のような動的型付け言語において、内部でもレイヤをまたぐ場合はきちんと定義されたデータモデルを利用することで、知らない間にデータモデルが変わっていた、というようなケースを防ぐことができます。
Python には標準でスキーマバリデーションライブラリがないため 3rd パーティのものを使うことになりますが、様々なライブラリがあるので比較してみました。
比較対象のライブラリ概要
※Python バージョンは 3.9.0 を利用します。
lib | version | Github Star (2020/1/5) | memo |
---|---|---|---|
pydantic | 1.7.3 | 5.0k | 今回の比較対象の中では最も新しい。 FastAPI に組み込まれている。 |
marshmallow | 3.10.0 | 5.2k | 最も人気。Flask や SQLAlchemy といった人気ライブラリ とのインテグレーションもある。 |
attrs (+ cattrs) | 20.3.0, (1.1.2) | 3.3k | Python クラスを簡単に定義するために開発されたもの。 標準の dataclass で"Why not just use attrs ?"と注釈されている。 cattrs は、attrs にシリアライズ・デシリアライズを可能にするライブラリ。 今回は併用する前提で比較。 |
cerberus | 1.3.2 | 2.3k | eveという Flask ベースのフレームワークで採用されている。 eve 自体を利用している例は見たことがないが、 cerberus 単体では利用されている印象。 |
比較対象の選定の基準
- スキーマ定義が可能なこと
- バリデーション定義が可能なこと
- ある程度アクティブなプロジェクトであること
- HTTP リクエストのパースなど、特定の用途のみではなく、幅広い用途に利用できること。
候補から除外したライブラリ
- schematics
- Github Star 数は 2.4k とまぁまぁ多いですが、2018 年 12 月を最後にコミットが途絶えており、PR も放置されている状態。特殊な機能もなく選定される理由はないので除外。
- colander
- django-rest-framework
- flask-restful
- この 3 つはいずれもスキーマバリデーションが可能ですが、HTTP リクエストパースのために特定のフレームワークと共に利用されることを前提しているので除外
- jsonschema
- デフォルト値の適用などの変換処理がないため除外
機能の比較
スキーマ定義に関する機能
pydantic | marshmallow | attrs | cerberus | |
---|---|---|---|---|
スキーマ定義の方法 | class | class | class | dict |
required 指定 | Yes | Yes | Yes | Yes |
nullable 可否の指定 | Yes | Yes | Yes | Yes |
default の指定 | Yes | Yes | Yes | Yes |
default factory の指定 | Yes | Yes | Yes | Yes |
カスタム型 | Yes | Yes | Yes | Yes |
定義のネスト | Yes | Yes | No | Yes |
定義の再利用 (継承など) | Yes | Yes | No | Yes |
定義の動的生成 | Yes | No | No | Yes |
型アノテーション | Yes | No | Yes | No |
コメント
- pydantic は高機能
- cerberus は唯一、dict でスキーマ定義をする
- attrs は複雑な用途には不向き
- marshmallow も高機能だが、スキーマクラスをデータオブジェクトとして利用できない点が pydantic / attrs との差。適切なデータオブジェクトへの変換はユーザーが責任を持つ。
バリデーション定義に関する機能
pydantic | marshmallow | attrs | cerberus | |
---|---|---|---|---|
型バリデーション | Yes | Yes | Yes | Yes |
Union 型バリデーション | Yes | No * | No | Yes |
範囲バリデーション(ge / le / gt / lt) | Yes | Yes | No | Yes |
length バリデーション | Yes | Yes | No | Yes |
正規表現バリデーション | Yes | Yes | Yes | Yes |
oneOf バリデーション | Yes | Yes | No | Yes |
カスタムバリデーション | Yes | Yes | Yes | Yes |
複数フィールドにまたがるバリデーション | Yes | Yes | No | No |
未定義のフィールドの扱い(無視・エラー選択) | Yes | Yes | No | Yes |
コメント
- marshmallow はプラグインを別途インストールすることで Union にも対応できるようです
- attrs はバリデータの機能が弱いようです。
シリアライズ・デシリアライズに関する機能
pydantic | marshmallow | attrs | cerberus | |
---|---|---|---|---|
model -> dict | Yes | Yes | Yes | No |
dict -> model | Yes | Yes | Yes | No |
※model -> json 文字列 | Yes | No | No | No |
json 文字列 -> ※model | Yes | No | No | No |
フィールド名のエイリアス | Yes | No | No | No |
フィールド除外(シリアライズ) | Yes | Yes | No ? | No |
カスタムシリアライザ | Yes | Yes | Yes | No |
環境変数読み込み(デシリアライズ) | Yes | No | No | No |
※ model <-> json 文字列変換には、datetime, enum, ネストしたモデル型を持つモデルを対象とします。datetime や Enum といった型を、特にカスタムコードを追加することなく文字列化可能かを検査しています。
コメント
- marshmallow について
- Enum 型への対応は プラグインを使えば可能です。
- datetime 型を dict からモデルに変換する場合、文字列に直さないと変換できません。
- モデルデータを保持するクラスは、ライブラリを使ったスキーマとは別に自分で用意しなければいけないため、型定義が二重になる。
- attrs について
cattr
を使えばdatetime
にも対応できますが、追加のコードが必要です。- 使い慣れていないので、実は Yes の項目もあるかもです。
- cerberus について
- そもそもモデルクラスのインスタンスに変換することをサポートしていません。
- pydantic
総合的な使い心地について
個人的な視点も入ってしまいますが、使い心地についても評価してみようと思います。
pydantic | marshmallow | attrs | cerberus | |
---|---|---|---|---|
全体的な機能の充実度 | とても良い | とても良い | イマイチ | 普通 |
スキーマの定義しやすさ | とても良い | 良い | 良い | イマイチ |
コード補完の効きやすさ | とても良い | 良い | 良い | イマイチ |
バリデーションの充実度 | とても良い | とても良い | イマイチ | 良い |
パフォーマンス ※ | 良い? | 普通? | とても良い? | イマイチ? |
コメント
- フィールドに自然に型アノテーションをつけられる Pydantic はやはり書きやすいです。Pycharm プラグインも開発されているのも良いです。
- パフォーマンスについて
- Pydantic のパフォーマンス比較と、こちらのブログから。参考程度の比較になります。
まとめ
Pydantic びいきの比較になってしまったような気もしますが、概ね以下の通りです。
- pydantic
- 機能の充実度と書きやすさが両立されており、まず最初に候補に入れるべきライブラリ。
- Python3.6 以上にしか対応していないので、古いシステムには使えない。
- marshmallow
- Pydantic と同等に近い充実度。pydantic よりも歴史があるので、事例も多い。
- スキーマからモデルクラスを作る場合、自分で用意しなきゃいけないのが面倒。
- 別途インストールするプラグインも多くあるので、機能として足りない部分を補うことも期待できる。
- Flask を使うのなら、Pydantic よりもこちらのほうが事例が多そう。flask-marshmallowというライブラリもある。
- attrs
- そもそもがバリデーションライブラリではなく、dataclass のようにクラスを書きやすくするライブラリなので、バリデーションについては弱め。
- 機能の充実度は低いですが、パフォーマンスは良いので要件の厳しい部分では使えそう。
- cerberus
- 今回の中では唯一、dict でスキーマを定義するタイプ。
- jsonschema っぽい独自構文で定義するのだが、コード補完も効かないので定義するのが大変。
- あまりこれを使うシーンは思い浮かばないのが正直なところ。