Pythonスキーマバリデーションライブラリ比較 (pydantic, marshmallow, attrs, cerberus)

Authors
  • avatar
    Twitter
    @__Attsun__
    Published on

ウェブ API の作成など、外部からやってくるデータを安全に捌く上で、スキーマ定義とバリデーションは非常に重要です。

また、特に Python のような動的型付け言語において、内部でもレイヤをまたぐ場合はきちんと定義されたデータモデルを利用することで、知らない間にデータモデルが変わっていた、というようなケースを防ぐことができます。

Python には標準でスキーマバリデーションライブラリがないため 3rd パーティのものを使うことになりますが、様々なライブラリがあるので比較してみました。

比較対象のライブラリ概要

※Python バージョンは 3.9.0 を利用します。

lib                    versionGithub Star
(2020/1/5)
memo
pydantic1.7.35.0k今回の比較対象の中では最も新しい。
FastAPI に組み込まれている。
marshmallow3.10.05.2k最も人気。Flask や SQLAlchemy といった人気ライブラリ
とのインテグレーションもある。
attrs
(+ cattrs)
20.3.0, (1.1.2)3.3kPython クラスを簡単に定義するために開発されたもの。
標準の dataclass で"Why not just use attrs ?"と注釈されている。
cattrs は、attrs にシリアライズ・デシリアライズを可能にするライブラリ。
今回は併用する前提で比較。
cerberus1.3.22.3keveという Flask ベースのフレームワークで採用されている。
eve 自体を利用している例は見たことがないが、
cerberus 単体では利用されている印象。

比較対象の選定の基準

  • スキーマ定義が可能なこと
  • バリデーション定義が可能なこと
  • ある程度アクティブなプロジェクトであること
  • HTTP リクエストのパースなど、特定の用途のみではなく、幅広い用途に利用できること。

候補から除外したライブラリ

  • schematics
    • Github Star 数は 2.4k とまぁまぁ多いですが、2018 年 12 月を最後にコミットが途絶えており、PR も放置されている状態。特殊な機能もなく選定される理由はないので除外。
  • colander
  • django-rest-framework
  • flask-restful
    • この 3 つはいずれもスキーマバリデーションが可能ですが、HTTP リクエストパースのために特定のフレームワークと共に利用されることを前提しているので除外
  • jsonschema
    • デフォルト値の適用などの変換処理がないため除外

機能の比較

スキーマ定義に関する機能

pydanticmarshmallowattrscerberus
スキーマ定義の方法classclassclassdict
required 指定YesYesYesYes
nullable 可否の指定YesYesYesYes
default の指定YesYesYesYes
default factory の指定YesYesYesYes
カスタム型YesYesYesYes
定義のネストYesYesNoYes
定義の再利用 (継承など)YesYesNoYes
定義の動的生成YesNoNoYes
型アノテーションYesNoYesNo

コメント

バリデーション定義に関する機能

pydanticmarshmallowattrscerberus
型バリデーションYesYesYesYes
Union 型バリデーションYesNo *NoYes
範囲バリデーション(ge / le / gt / lt)YesYesNoYes
length バリデーションYesYesNoYes
正規表現バリデーションYesYesYesYes
oneOf バリデーションYesYesNoYes
カスタムバリデーションYesYesYesYes
複数フィールドにまたがるバリデーションYesYesNoNo
未定義のフィールドの扱い(無視・エラー選択)YesYesNoYes

コメント

  • marshmallow はプラグインを別途インストールすることで Union にも対応できるようです
  • attrs はバリデータの機能が弱いようです。

シリアライズ・デシリアライズに関する機能

pydanticmarshmallowattrscerberus
model -> dictYesYesYesNo
dict -> modelYesYesYesNo
※model -> json 文字列YesNoNoNo
json 文字列 -> ※modelYesNoNoNo
フィールド名のエイリアスYesNoNoNo
フィールド除外(シリアライズ)YesYesNo ?No
カスタムシリアライザYesYesYesNo
環境変数読み込み(デシリアライズ)YesNoNoNo

※ model <-> json 文字列変換には、datetime, enum, ネストしたモデル型を持つモデルを対象とします。datetime や Enum といった型を、特にカスタムコードを追加することなく文字列化可能かを検査しています。

コメント

総合的な使い心地について

個人的な視点も入ってしまいますが、使い心地についても評価してみようと思います。

pydanticmarshmallowattrscerberus
全体的な機能の充実度とても良いとても良いイマイチ普通
スキーマの定義しやすさとても良い良い良いイマイチ
コード補完の効きやすさとても良い良い良いイマイチ
バリデーションの充実度とても良いとても良いイマイチ良い
パフォーマンス ※良い?普通?とても良い?イマイチ?

コメント

まとめ

Pydantic びいきの比較になってしまったような気もしますが、概ね以下の通りです。

  • pydantic
    • 機能の充実度と書きやすさが両立されており、まず最初に候補に入れるべきライブラリ。
    • Python3.6 以上にしか対応していないので、古いシステムには使えない。
  • marshmallow
    • Pydantic と同等に近い充実度。pydantic よりも歴史があるので、事例も多い。
    • スキーマからモデルクラスを作る場合、自分で用意しなきゃいけないのが面倒。
    • 別途インストールするプラグインも多くあるので、機能として足りない部分を補うことも期待できる。
    • Flask を使うのなら、Pydantic よりもこちらのほうが事例が多そう。flask-marshmallowというライブラリもある。
  • attrs
    • そもそもがバリデーションライブラリではなく、dataclass のようにクラスを書きやすくするライブラリなので、バリデーションについては弱め。
    • 機能の充実度は低いですが、パフォーマンスは良いので要件の厳しい部分では使えそう。
  • cerberus
    • 今回の中では唯一、dict でスキーマを定義するタイプ。
    • jsonschema っぽい独自構文で定義するのだが、コード補完も効かないので定義するのが大変。
    • あまりこれを使うシーンは思い浮かばないのが正直なところ。