Python 3.15: 「引数が渡されなかった」を表す値は組み込みの sentinel で作る
None も正当な値として受け付けたい引数では、これまで MISSING = object() を自作していた。3.15 からは MISSING = sentinel("MISSING") で、見やすい repr・型ヒントでの利用・コピーや pickle をしても同一性が保たれる番兵が作れる(PEP 661)。
これまでの書き方の困りごと
python
_MISSING = object()
def get(key, default=_MISSING):
...
if default is _MISSING:
raise KeyError(key)help()やエラーメッセージに<object object at 0x7f...>と出て読みにくいcopy.deepcopyや pickle を通ると別のオブジェクトになり、isの比較が壊れる- 型ヒントで「この番兵か int」を書きにくい(
Enumを作るなどの回り道が必要だった)
3.15 の書き方
python
MISSING = sentinel("MISSING")
def get(key: str, default: int | MISSING = MISSING) -> int:
if default is MISSING:
raise KeyError(key)
return default
print(MISSING) # MISSING- 比較は今まで通り
isで行う。 |で型式に使える。コピーしても同一性が保たれ、モジュールの名前と変数名でインポートできる位置に置けば pickle も通る。
注意点
- 3.15 より前もサポートするライブラリでは、まだ使えない(
typing_extensionsなどの互換実装があるかは要確認)。 - 型チェッカー(mypy / pyright など)が
int | MISSINGを理解するかはそれぞれの対応状況による。 - 同じく 3.15 で組み込みに入った
frozendict、明示的な遅延 import(lazy import)もあわせて確認しておくとよい。3.15 の別の変更は Python 3.15: contextmanager をジェネレータ・async 関数のデコレータにしたときの挙動が変わる。
出典
- @driscollis · 2026-10-21
- What's new in Python 3.15(PEP 661: Add sentinel built-in type): docs.python.org