Python 3.14ではアノテーションが原則としてアクセス時に遅延評価されるため、関数定義が成功しても、未定義の型名をFormat.VALUEで読み取る段階でNameErrorになることがあります。表示や記録だけならFormat.STRING、未解決参照を保持して扱える解析処理ならFormat.FORWARDREF、実際の型オブジェクトが必要なら名前の定義・import完了後にFormat.VALUEを使います。
annotationlib.get_annotations()を使うだけでは解決しません。既定のformatはFormat.VALUEなので、用途に合う形式を明示する必要があります。Python 3.14のannotationlib公式資料では、VALUE、FORWARDREF、STRINGの3形式と、未定義名がある場合の違いが説明されています。
以下は2026年10月4日時点のPython 3.14公式資料に基づきます。
Python 3.13以前・3.14・future importの違い
| コードの状態 | 注釈の基本動作 | 未定義名が表面化する時点 |
|---|---|---|
| Python 3.13以前の通常の注釈 | 原則として定義時に評価 | 関数やクラスの定義時 |
| Python 3.14の通常の注釈 | 必要になるまで遅延評価 | __annotations__やVALUEで読む時 |
Python 3.14でfrom __future__ import annotationsを使用 | 従来どおり文字列化 | 文字列を実値へ解決する処理の時 |
Python 3.14ではPEP 649・PEP 749による遅延評価が導入済みです。What’s New in Python 3.14によると、実行時に注釈を読むコードは取得形式の見直しが必要な場合があります。future importは3.14でも文字列化動作を維持しています。
最小例:定義は成功し、VALUEで読むと失敗する
次のコードはPython 3.14で、future importを使わない例です。Missingの定義前でもparse自体は定義できますが、注釈を値として読むと未定義名が評価されます。
from annotationlib import Format, ForwardRef, get_annotations
def parse(x: Missing) -> None:
pass
try:
print(parse.__annotations__)
except NameError as exc:
print(type(exc).__name__)
print(get_annotations(parse, format=Format.STRING))
refs = get_annotations(parse, format=Format.FORWARDREF)
print(isinstance(refs['x'], ForwardRef))
class Missing:
pass
annotations = get_annotations(parse, format=Format.VALUE)
print(annotations['x'] is Missing)
Format.STRINGはソースに近い文字列を返し、Format.FORWARDREFは解決できる値を実値、未定義名をForwardRefとして返します。この例では、型の定義後にVALUEで読み直せば、Missingの実クラスを取得できます。FORWARDREFの結果には、list[Missing]のような型の内部に参照が残る場合もあるため、消費側がその構造を扱えることも確認します。文字列は空白の正規化などで変わる可能性があり、厳密なソース復元用途ではありません。

実プロジェクトでの切り分け
- 実行版を確認する:
python --versionとpython -c "import sys; print(sys.executable)"で、想定したPython 3.14を使っているか確認します。 - future importを確認する:対象モジュール先頭の
from __future__ import annotationsの有無を記録します。3.14の通常動作と文字列化モードを混同しないでください。 - 失敗時点を分ける:定義時か、
__annotations__、get_annotations()、inspect.signature()などを呼んだ時かを確認します。 - 未定義名の出所を探す:後で定義されるクラスか、循環importか、
if TYPE_CHECKING:内だけでimportしている型かを確認します。TYPE_CHECKING内の名前は通常の実行時には定義されません。 - 消費側が必要とする形式を決める:ドキュメント表示ならSTRING、未解決参照を認識できる解析ならFORWARDREF、DIや実行時検証など実型が必要ならimport完了後のVALUEを選びます。
- 第三者ライブラリなら対応版を確認する:内部属性を書き換えず、公式のPython 3.14対応状況を確認します。
Python公式のアノテーションのベストプラクティスでは、3.14以降は直接属性を読むよりannotationlib.get_annotations()を使うことが推奨されています。直接代入や削除でエラーを隠す方法は避けてください。
inspect.signatureを表示目的で使う
シグネチャの表示だけが目的なら、Python 3.14で追加されたannotation_formatを指定できます。
import inspect
from annotationlib import Format
def parse(x: Missing) -> None:
pass
signature = inspect.signature(
parse,
annotation_format=Format.STRING,
)
print(signature)
inspect.signature公式資料では、annotation_format=Format.STRINGで文字列形式を選べるとされています。この引数をPython 3.13向けコードへそのまま持ち込まないでください。
STRINGとFORWARDREFも安全なサンドボックスではない
公式のセキュリティ説明にあるとおり、STRINGやFORWARDREFを選んでも、任意の注釈が絶対に評価されず、例外も起きないとは限りません。カスタムのannotate関数や注釈式によって、例外やコード実行が発生する可能性があります。未信頼コードの注釈を安全に解析する仕組みとして扱わないでください。
よくある質問
get_annotations()へ変えればNameErrorは消えますか?
既定形式がVALUEなので、未定義名があれば同様に失敗します。目的に応じてformatを明示します。
eval_str=Falseなら遅延注釈を評価しませんか?
万能な停止指定ではありません。eval_strは主にfuture importなどで文字列化された注釈を再評価するかに関わり、通常の3.14遅延注釈をVALUEで読む動作とは分けて考えます。future importで文字列化された注釈は、既定のVALUEでもそのまま文字列を返します。実型へ解決したい場合は、必要な名前を定義した後でget_annotations(obj, eval_str=True, format=Format.VALUE)のように文字列の評価を明示します。eval_str=TrueはVALUE以外との組み合わせではエラーになります。
まとめ
Python 3.14のNameErrorは、遅延評価が壊れたのではなく、未定義名をVALUEとして読む時点へエラーが移った場合があります。まず注釈を読む目的を確認し、STRING、FORWARDREF、VALUEを選び分けてください。


コメント