typing.overload 仅为类型检查器提供多签名提示,函数体仍需手动处理逻辑;必须将多个无函数体的@overload声明置于最前,最后跟一个未装饰的实际实现。

typing.overload 不是用于运行时重载,而是为类型检查器(如 mypy、PyCharm、VS Code 的 Pylance)提供多签名提示,让静态类型检查更精确。函数体本身仍只有一个实现,需手动处理不同参数组合的逻辑。
基本用法:声明多个 @overload 装饰的存根
必须把所有 @overload 声明放在最前面,且**不能有函数体**(只写 ... 或 pass),最后跟一个**未装饰的实际实现**(带完整逻辑)。
例如,定义一个根据输入类型返回不同结果的 parse 函数:
from typing import overload, Union, List, Optional
@overload
def parse(value: str) -> int: ...
@overload
def parse(value: List[str]) -> List[int]: ...
@overload
def parse(value: None) -> None: ...
def parse(value: Union[str, List[str], None]) -> Union[int, List[int], None]:
if isinstance(value, str):
return int(value)
elif isinstance(value, list):
return [int(x) for x in value]
else:
return None
类型检查器会根据调用时传入的参数类型,从上面的 @overload 中匹配最合适的签名,从而推断出返回类型。
立即学习“Python免费学习笔记(深入)”;
关键规则:顺序、实现与类型检查协同
-
@overload 函数必须严格按参数类型“从具体到宽泛”排列(比如
str在前,Union[str, int]在后),否则 mypy 可能匹配错误签名 - 实际实现函数**不能加 @overload**,且其签名必须能兼容所有重载声明(通常是用联合类型或
Any) - 运行时不会触发任何分发逻辑——所有类型分支靠
isinstance、type()等手动判断 - IDE 和 mypy 只看
@overload声明做推导,不执行实现体;所以即使实现体写错,类型检查也可能通过(但运行时报错)
常见场景:可选参数 + 不同返回类型
比如一个读取配置的函数,支持传 key 返回值,或不传 key 返回整个 dict:
from typing import overload, Dict, Any, Optional
@overload
def config(key: str) -> Any: ...
@overload
def config(key: None = None) -> Dict[str, Any]: ...
def config(key: Optional[str] = None) -> Union[Any, Dict[str, Any]]:
data = {"host": "localhost", "port": 8000}
if key is None:
return data
return data.get(key)
调用 config("host") 时,类型检查器知道返回 Any;调用 config() 时,知道返回 Dict[str, Any],补全和类型推导更准。
注意点:不是运行时多态,也不支持装饰器叠加
- 不能对同一个函数同时用
@overload和@lru_cache等装饰器(@overload必须紧贴函数名) - 不支持基于返回类型重载(只看参数)
- 如果参数类型有重叠(如两个都接受
int),mypy 会选择第一个匹配项,容易误判——应避免歧义签名 - 纯运行时动态分发建议用
functools.singledispatch,它和@overload解决的是不同问题










