2026年10月8日、Pythonのデータ検証ライブラリPydanticの2.14.0が公開されました。FastAPIの裏側でも使われている、とても利用者の多いライブラリです。
今回の目玉は、正式版の公開を目前に控えたPython 3.15への対応です。あわせて、値が送られてこなかったことを表すMISSINGという仕組みが、実験的な機能から正式な機能になりました。
NoneとMISSINGはどう違うのか、と疑問に思った方もいるでしょう。今回は、その違いを実際に動かしながら見ていきます。
まずは何が変わったのかを整理しよう¶
最初に、今回取り上げる変更を表にまとめます。内容は、Pydanticの公式リポジトリにある変更履歴にもとづいています。
| 変更 | 中身 |
|---|---|
| Pythonの対応範囲 | 3.9のサポートを終了し、3.15に対応 |
| Python 3.15の新機能 | frozendict、TypeForm、lazy importに対応 |
| MISSING | 実験的な機能から正式な機能へ |
| 新しい制約 | fractionとtimedeltaにmultiple_ofを指定できる |
| 細かな修正 | 検証やJSON Schemaの生成まわりの不具合を多数修正 |
PyPIの記録によると、2.14.0が必要とするPythonは3.10以上です。3.9で動かしている場合、pip installしても2.14は入らず、2.13系のままになります。
Pydanticそのものがまだよくわからない方は、先にこちらを読んでおくと話がつながります。【関連記事】Pydantic v2とは?
Python 3.15の新機能に対応した¶
変更履歴によると、2.14.0b2の段階でPython 3.15の新しい機能への対応が入りました。その内容が、今回の正式版にそのまま含まれています。
frozendictを型として使える¶
Python 3.15では、書き換えられない辞書frozendictが組み込みの型として加わります。Pydantic 2.14では、このfrozendictをモデルのフィールドの型として使えるようになりました。
frozendictそのものについては、3.15の新機能をまとめた記事で紹介しています。【関連記事】Python 3.15の新機能を先取り解説!
TypeFormとlazy importにも対応¶
TypeFormは、型そのものを値として受け渡すときに、型チェッカーが正しく理解できるようにする仕組みです。Pydanticでは、TypeAdapterなどで型を渡す場面の型チェックが、より正確になります。
もう1つが、3.15の目玉機能であるlazy importへの対応です。モジュールを実際に使う瞬間まで読み込みを遅らせる仕組みで、プログラムの起動を速くする効果が期待されています。
Python 3.15の正式版は、10月9日の公開が予定されています。主要なライブラリがこうして先に対応してくれると、新しいPythonへ安心して移れるようになります。
3.15の公開日程が変わった経緯は、先日の記事で取り上げました。【関連記事】Python 3.15の正式版は10月9日に延期
未入力を表すMISSINGが正式な機能に¶
今回のニュースで、学習者にとっていちばん面白いのがMISSINGです。Pydanticのドキュメントによると、MISSINGは2.12で実験的な機能として加わり、2.14で実験的という扱いが外れました。
これからは、from pydantic import MISSINGと書くだけで使えます。では、MISSINGは何のためにあるのでしょうか。
NoneとMISSINGは何が違うのか¶
Pythonでは、値がないことを表すのにNoneがよく使われます。けれども、Noneには2つの意味が混ざってしまうことがあります。
たとえば、プロフィールを更新するWeb APIを考えてみてください。自己紹介を空にしたいという指示と、自己紹介には触れないという指示は、まったく別のものですよね。
両方をNoneで表すと、プログラムからはこの2つを区別できません。MISSINGは、そもそも値が送られてこなかったことを表すための専用の目印です。
Noneの基本については、こちらで詳しく解説しています。【関連記事】PythonのNoneとは?
MISSINGを実際に動かしてみる¶
では、プロフィール更新の例を実際にコードにしてみましょう。ニックネームと自己紹介の2つのフィールドを持つモデルで、どちらも既定値をMISSINGにしておきます。
from pydantic import MISSING, BaseModel
class ProfileUpdate(BaseModel):
nickname: str | None | MISSING = MISSING
bio: str | None | MISSING = MISSING
# ニックネームだけ変えたい
a = ProfileUpdate(nickname="taro")
# 自己紹介を空(None)にしたい
b = ProfileUpdate(bio=None)
print(a.model_dump())
print(b.model_dump())
print(a.bio is MISSING, b.bio is MISSING)
新しい仮想環境にPydantic 2.14.0を入れ、手元のPython 3.11で実行した結果です。
{'nickname': 'taro'}
{'bio': None}
True False
1行目では、送られてこなかったbioが、model_dump()の結果から自動的に消えています。2行目では、明示的にNoneを指定したbioは、ちゃんとNoneとして残りました。
ドキュメントによると、MISSINGが入ったフィールドは、シリアライズのときに自動で出力から外されます。シリアライズとは、モデルを辞書やJSONに変換することです。
値を判定するときはisを使う¶
3行目のように、MISSINGかどうかを調べるときはisで比べます。ドキュメントの例でも、conf.timeout if conf.timeout is not MISSING else defaults['timeout']のように、isで判定してから既定値を補う書き方が紹介されています。
ちなみにドキュメントには、MISSINGは実行時にはPython 3.15で加わるsentinelのしくみで実装されている、と書かれています。sentinelは、こうした特別な目印の値を作るための新しい組み込みの仕組みです。
私は10年ほどエンジニアとして開発に関わってきましたが、更新APIで送られてこなかった項目をNoneと同じに扱ってしまい、ユーザーの入力済みのデータを空で上書きした事故を見たことがあります。こうした区別を、ライブラリが標準の機能として用意してくれるのは心強いですね。
これまでのexclude_unsetとの違い¶
実は、送られてこなかった項目を出力から外すだけなら、これまでもmodel_dump()のexclude_unset=Trueで実現できました。ドキュメントでも、MISSINGはexclude_unsetの代わりに使える、と紹介されています。
では、何が違うのでしょうか。従来の書き方とMISSINGを使った書き方を、並べて動かしてみます。
from pydantic import MISSING, BaseModel
class OldStyle(BaseModel):
bio: str | None = None
class NewStyle(BaseModel):
bio: str | None | MISSING = MISSING
print(OldStyle().model_dump())
print(OldStyle().model_dump(exclude_unset=True))
print(NewStyle().model_dump())
print(NewStyle.model_json_schema()["properties"]["bio"])
実行結果は次のとおりです。
{'bio': None}
{}
{}
{'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'Bio'}
従来の書き方では、exclude_unset=Trueを付け忘れると、送られてこなかったbioがNoneとして出力されてしまいます。MISSINGを使えば、付け忘れの心配がなく、モデルの定義だけで意図が伝わるのが大きな違いです。
違いを表にまとめておきます。
| 比べる点 | exclude_unset | MISSING |
|---|---|---|
| 指定する場所 | model_dump()を呼ぶたび | モデルの定義に1回だけ |
| 付け忘れたとき | Noneとして出力される | 心配なし |
| 値を見て判定 | 別の方法で調べる必要がある | isで直接判定できる |
| JSON Schema | 通常どおり | MISSINGは現れない |
最後の行のとおり、MISSINGはJSON Schemaには現れません。API仕様書を自動生成している場合も、利用者側から見た型は文字列かnullのままで変わらないので安心です。
そのほかの変更点¶
ほかにも、2.14では細かな改善がたくさん入っています。変更履歴から、初心者にも関係しそうなものをいくつか紹介します。
| 変更 | 意味 |
|---|---|
| fractionとtimedeltaにmultiple_ofを追加 | ある値の倍数かどうかを検証できる |
| create_model()に__namespace__を追加 | 動的に作るモデルの名前空間を指定できる |
| NameEmailで改行を拒否 | 名前付きのメールアドレスに改行が入るのを防ぐ |
| model_configを書き換えない | 設定がほかのモデルへ思わぬ形で伝わるのを防ぐ |
変更履歴には、バージョン管理の方針上は互換性を壊さない扱いの、小さな変更もいくつか含まれていると書かれています。上げる前に一度目を通しておくよう、案内されています。
特に、検証やJSON Schemaの生成まわりでは多くの修正が入りました。これまでの動きに頼ったテストがある場合は、2.14で一通り流しておくと安心です。
上げる前にやっておきたいこと¶
最後に、2.13から2.14へ上げるときの確認ポイントを整理します。大きな互換性の問題は少ない更新ですが、次の点は押さえておきましょう。
| 順番 | 確認すること |
|---|---|
| 1 | 動かしているPythonが3.10以上か |
| 2 | 変更履歴の小さな変更に、自分のコードが当てはまらないか |
| 3 | 実験的なMISSINGを使っていたなら、import文を書き換える |
| 4 | テストを2.14で一通り流して、結果が変わらないか |
FastAPIでAPIを作っている方は、Pydanticの更新がそのままAPIの入力チェックに影響します。FastAPIとPydanticの関係は、こちらで紹介しています。【関連記事】PythonのFastAPIとは?
以前、入力チェックのライブラリを上げたら、エラーメッセージの文面がわずかに変わり、それを画面に出していたテストがまとめて落ちたことがあります。エラーメッセージの文面には頼りすぎないようにしておくと、こうした更新に強くなります。
まとめ¶
Pydantic 2.14.0が2026年10月8日に公開されました。Python 3.9のサポートを終え、3.15のfrozendictやlazy importに対応し、MISSINGが正式な機能になりました。
NoneとMISSINGを使い分けると、値を空にしたいのか、そもそも送られてこなかったのかを、はっきり区別できます。更新用のAPIを作るときに、ぜひ思い出してみてください。
ここまでお読みいただきありがとうございました。