from __future__ import annotations – 打開 Python 型別提示未來的關鍵語句

關鍵字__future__annotationsPEP 563PEP 649Python 3.7+


1. 為什麼需要 __future__



Python 自 1990 年代初就被設計為動態型別語言。隨著大型專案的增長,靜態型別檢查程式碼可讀性變得愈發重要。為此,Python 引入了型別提示(type hints),並推出了 typing 模組。

然而,早期的型別提示在執行時即刻解析,導致以下問題:

問題 範例
循環引用 class A: pass
class B(A): pass
在型別提示中直接使用 A 會觸發 NameError
延遲評估 from typing import List
def f(x: List[int]) -> List[int]: ...
函式定義時必須已經匯入 List
字串延遲 def f(x: "MyClass") -> "MyClass": ...
若要以字串方式延遲型別,必須使用 __future__

為解決這些問題,PEP 563(Python 3.7)引入了 from __future__ import annotations


2. from __future__ import annotations 是什麼?

定義:自 Python 3.7 起的功能,將所有型別提示以字串形式延遲評估。

核心機制

  • 函式/方法定義時,型別提示被存成字串
  • 當實際需要型別(例如 typing.get_type_hints)時才進行延遲評估
  • 即使存在循環引用,也能避免 NameError

使用範例

# 未使用 __future__
class Node:
    def __init__(self, value: int, next: 'Node' = None):
        self.value = value
        self.next = next

# 使用 __future__
from __future__ import annotations

class Node:
    def __init__(self, value: int, next: Node | None = None):
        self.value = value
        self.next = next

注意:使用 __future__ 後,所有型別提示皆為字串;若需要 typing.get_type_hints 等函式,typing 模組會自動評估這些字串。


3. PEP 563 之後的變化



PEP 649 – 延遲評估的重新定義

  • Python 3.11 引入 PEP 649。
  • 即使使用 __future__,延遲評估仍只在真正需要時執行。
  • typing.get_type_hints 透過快取提升效能。

Python 3.12 之後

  • PEP 649 完全實作,__future__ 的延遲評估更為高效。
  • from __future__ import annotations 成為預設行為,大多數情況下不再需要額外宣告。

4. 實戰小技巧

情境 推薦做法 原因
循環引用 from __future__ import annotations 避免 NameError
大型專案 __future__ 宣告 + typing.get_type_hints 提升型別檢查效能
Python 3.11+ 可省略 __future__ 預設即為延遲評估
字串型別提示 使用 typing.TYPE_CHECKING 避免執行時不必要的匯入

範例:結合 typing.TYPE_CHECKING

from __future__ import annotations
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from .module_a import ClassA

class MyClass:
    def method(self, obj: ClassA) -> None:
        ...
  • TYPE_CHECKING靜態型別檢查器中為 True,但執行時為 False,因此不會觸發匯入。

5. 總結

  • from __future__ import annotations 使型別提示能延遲評估,從而避免循環引用與執行時錯誤。
  • Python 3.11 之後,延遲評估已成為預設行為,除非你使用 3.7~3.10 或需要明確控制評估時機,否則可省略此宣告。
  • 在專案中統一使用 __future__,並配合靜態型別檢查器(mypy、pyright 等),可顯著提升程式碼品質。

Tip:在專案中加入 __future__ 時,請確保整個程式碼庫皆使用,以維持一致性。


補充資料 - PEP 563: https://www.python.org/dev/peps/pep-0563/ - PEP 649: https://www.python.org/dev/peps/pep-0649/ - mypy 官方文件: https://mypy.readthedocs.io/en/stable/cheat_sheet.html


相關文章