它解决什么问题
Python 在解析函数签名时会立即对类型注解求值。如果类还没定义完就引用了自身,会抛 NameError:
class Node:
def __init__(self, next: Node = None): # NameError: name 'Node' is not defined
self.next = next
加上这一行就能解决:
from __future__ import annotations
class Node:
def __init__(self, next: Node = None): # 正常
self.next = next
原理是让 Python 把所有注解保存为字符串,不再立即解析。
核心效果
from __future__ import annotations
class User:
pass
def get_user() -> User:
return User()
print(get_user.__annotations__)
# {'return': 'User'} ← 字符串,不是 <class '__main__.User'>
没有这行时,__annotations__ 里存的是实际类对象;有了这行,全部变成字符串,运行时不解析。
解决循环引用
from __future__ import annotations
class A:
def test(self, b: B) -> None:
pass
class B:
def test(self, a: A) -> None:
pass
不加的话,定义 A 时 B 还不存在,报 NameError。
常见使用场景
FastAPI / Pydantic 模型互相引用:
from __future__ import annotations
from pydantic import BaseModel
class Article:
author: Author
class Author:
articles: list[Article]
SQLAlchemy ORM 关系:
from __future__ import annotations
from sqlalchemy.orm import Mapped, relationship
class User(Base):
posts: Mapped[list[Post]] = relationship()
class Post(Base):
user: Mapped[User] = relationship()
这是 FastAPI、Pydantic、SQLAlchemy 等库的文件开头几乎都有这行的原因。
运行时获取实际类型
如果需要在运行时把字符串注解解析回真实类型,用 typing.get_type_hints():
from __future__ import annotations
import typing
class Foo:
def bar(self) -> Foo:
return self
hints = typing.get_type_hints(Foo.bar)
print(hints)
# {'return': <class '__main__.Foo'>}
get_type_hints() 会在运行时把字符串注解解析成真实类型。
Python 版本说明
from __future__ import annotations来自 PEP 563,Python 3.7 引入- PEP 563 原本计划在 Python 3.10 成为默认行为,后来推迟,至今(Python 3.12+)仍需显式导入
- Python 3.10 引入了
X | Y联合类型语法,可以写int | None代替Optional[int],但前向引用问题from __future__ import annotations仍是最简洁的解法
一行导入,让注解写法更自由,是现代 Python 项目的常见约定。
