from __future__ import annotations – 打開 Python 型別提示未來的關鍵語句
關鍵字:
__future__、annotations、PEP 563、PEP 649、Python 3.7+
1. 為什麼需要 __future__?
Python 自 1990 年代初就被設計為動態型別語言。隨著大型專案的增長,靜態型別檢查與程式碼可讀性變得愈發重要。為此,Python 引入了型別提示(type hints),並推出了 typing 模組。
然而,早期的型別提示在執行時即刻解析,導致以下問題:
| 問題 | 範例 |
|---|---|
| 循環引用 | class A: passclass B(A): pass在型別提示中直接使用 A 會觸發 NameError |
| 延遲評估 | from typing import Listdef 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
相關文章:
目前沒有評論。