Python 类型注解:让你的代码会说话

Python 是动态语言,但这不意味着它「不能」有类型。从 3.5 引入的 typing 模块,到如今成了大型项目的标配。类型注解不改变运行时行为,却能让编辑器、人和静态检查器都更懂你的代码。

基础语法

def greet(name: str, times: int = 1) -> str:
    return name * times

就这么简单:参数后用 : 类型,函数后用 -> 返回类型

常用类型

from typing import Optional, List, Dict, Union, Callable

scores: List[int] = [90, 85, 77]
config: Dict[str, str] = {"host": "localhost"}
maybe: Optional[int] = None          # 等价于 Union[int, None]
callback: Callable[[int], bool] = lambda x: x > 0

Python 3.9+ 还能直接用内置容器:list[int]dict[str, int],更清爽。

用 mypy 守住底线

注解写了不检查等于没写。装个 mypy

pip install mypy
mypy my_module.py

它会揪出这类问题:

def add(a: int, b: int) -> int:
    return a + b

add("1", 2)   # mypy 报错:Argument 1 to "add" has incompatible type "str"

进阶:泛型与 Protocol

from typing import TypeVar, Protocol

T = TypeVar("T")

def first(items: list[T]) -> Optional[T]:
    return items[0] if items else None

class Renderable(Protocol):
    def render(self) -> str: ...

def show(obj: Renderable) -> None:
    print(obj.render())

Protocol 实现「结构化子类型」——只要对象有 render 方法,就自动满足条件,不用显式继承。

三个实在的好处

  1. 编辑器补全更聪明——知道 scoreslist[int],IDE 才敢给你提示 .append
  2. 重构不怕——改了函数签名,mypy 立刻告诉你哪几处没跟上。
  3. 新人读代码更快——类型就是最简明的文档。

类型注解不是给 Python 套上枷锁,而是给它装上护栏。项目越大,这点护栏越值钱。