mypy通过类型注解和静态推导判断变量类型,不运行代码;它保守推导、不依赖运行时行为,未注解处按上下文猜测(如x = 42 → int),但空列表推为list[Unknown]而非list[Any],歧义时直接报错而非妥协。

myPy 怎么知道变量类型?靠类型注解和类型推导
myPy 不运行代码,它只读取源码中的 type annotations(比如 def greet(name: str) -> int:),再结合内置规则做静态推导。没有注解的地方,它会尝试从赋值、函数返回、字面量等上下文猜类型,例如 x = 42 推出 x: int,y = [] 则默认为 y: list[Unknown](不是 list[Any],这点常被误解)。
关键点在于:myPy 的推导是保守的,不依赖运行时行为;它不看 isinstance 或 type(x) 这类动态判断,也不执行 __init__ 中的逻辑来“确定”类型。
- 未注解的函数参数默认为
Any,但会污染检查范围——后续对该参数的所有操作都可能绕过检查 -
None赋值不会自动引入Optional,必须显式写Union[str, None]或str | None(Python 3.10+) - 推导遇到歧义(如
z = []后又z.append("a"); z.append(1))会报错,而非妥协为list[Any]
为什么加了注解 myPy 还报错?常见类型不匹配场景
最典型的不是“没写注解”,而是注解和实际用法冲突。比如函数声明返回 str,但内部有 return None;或把 list[int] 传给期待 Sequence[str] 的参数——即使运行时能过,myPy 会直接拒绝。
这类错误背后是 myPy 对协变/逆变的严格处理:list 是不变的(invariant),所以 list[int] 和 list[float] 互不兼容;而 Sequence 是协变的,list[int] 可以当 Sequence[int] 用,但不能当 Sequence[float] 用。
立即学习“Python免费学习笔记(深入)”;
- 字典键类型错误:用
float当dict[str, int]的键 → 报Invalid index type - 泛型实例化遗漏:写了
def f(x: list) -> list:,但没写list[Any]或具体参数 → myPy 视为原始类型,多数操作受限 - 继承关系误判:子类实例传给期望父类的方法参数没问题,但反过来(父类实例传给只接受子类的参数)会报错
myPy 怎么处理第三方库?靠 stub 文件和隐式 Any 回退
没提供类型信息的第三方模块(比如早期的 requests 或自定义未注解包),myPy 默认将其所有内容视为 Any —— 这不是“信任”,而是“放弃检查”。真正启用检查,得靠 .pyi stub 文件或已集成类型提示的版本(如 requests>=2.29.0 带了部分类型)。
你可以用 mypy --show-traceback 看它到底从哪加载了类型信息:是内建 stub(stdlib/)、第三方 stub(site-packages/mypy/typeshed/)、还是项目里的 .pyi。如果路径显示 no library stubs,那对应模块基本就是盲区。
- 用
pip install types-requests补充 stub,但注意版本对齐(types-requests对应requests版本号) - 自己写 stub 时,函数签名必须和原函数一致,连默认参数顺序都不能错,否则 myPy 会静默忽略该 stub
- 用
# type: ignore抑制报错很危险:它会让整行失去类型保护,且不会警告你是否过度使用
为什么 myPy 检查慢?类型约束求解是核心开销
myPy 不是简单做字符串匹配,它把整个模块抽象成类型约束系统(类似逻辑编程),然后调用约束求解器判断是否存在满足所有注解和推导的类型赋值方案。函数调用、泛型嵌套、重载决议都会生成大量约束,尤其在大型文件或深度泛型链(如 Callable[[list[dict[str, Optional[T]]]], Awaitable[Union[U, V]]])中,求解时间明显上升。
这不是 bug,是设计使然:它宁可多花几秒确认安全,也不愿漏掉一个潜在类型错误。
- 禁用
--fast-parser(默认开启)反而可能更慢,因为旧解析器无法跳过注释和字符串中的伪注解 - 避免在类型表达式里用复杂计算,比如
Union[*tuple_of_types]或动态构建的Literal,myPy 无法静态展开 - 单文件检查快,但跨模块联合检查(尤其是循环 import + 泛型)容易触发重复求解,此时
--cache-dir能显著提速
类型检查的本质是权衡:越严格的约束,越高的正确性保障,也越重的分析成本。很多人卡在“为什么改一行就多出十个错”,其实不是工具太严,是之前那一行恰好暴露了长期积累的类型模糊点。







