使用mypy时遭遇泛型类型转换的意外类型推断问题
MyPy类型推断异常问题:为何会推断出
Callable[[str], Never]? 问题背景
使用mypy 1.9.0(Python 3.12.3)进行类型检查时,遇到不符合预期的类型推断行为:mypy将预期类型错误推断为Callable[[str], Never],无法理解该错误的产生原因。
复现代码
from typing import Generic, TypeVar, Callable, reveal_type S1 = TypeVar('S1') F1 = TypeVar('F1') I = TypeVar('I') class Node(Generic[I, S1, F1]): def __init__(self, callback: Callable[[I], S1 | F1]): self.callback: Callable[[I], S1 | F1] = callback class Succ1: ... class Fail1: ... def func1(_: str) -> Succ1 | Fail1: return Succ1() n1 = Node(func1) res1 = n1.callback("str") reveal_type(n1)
MyPy报错信息
% mypy isolated_example2.py isolated_example2.py:25: error: Need type annotation for "n1" [var-annotated] isolated_example2.py:25: error: Argument 1 to "Node" has incompatible type "Callable[[str], Succ1 | Fail1]"; expected "Callable[[str], Never]" [arg-type] isolated_example2.py:27: note: Revealed type is "isolated_example2.Node[builtins.str, Any, Any]" Found 2 errors in 1 file (checked 1 source file)
最小复现案例
后续排查发现问题与TypeVar的联合操作相关,最小复现代码如下:
from typing import TypeVar S1 = TypeVar('S1') F1 = TypeVar('F1') def func(arg: S1 | F1): return arg func(None)
问题原因分析
这个问题的核心在于未绑定约束的独立TypeVar在联合类型中会被MyPy特殊处理:
- 在
Node类的定义中,S1和F1是两个无约束的独立TypeVar。当MyPy尝试推断Node的类型参数时,需要让Callable[[I], S1 | F1]与传入的Callable[[str], Succ1 | Fail1]匹配。 - MyPy的类型推断逻辑无法自动将联合类型的分支分别绑定到独立的TypeVar上——它会认为
S1 | F1需要同时满足联合类型的所有分支,而唯一能同时满足这一条件的只有Never(空类型),因此就出现了预期类型为Callable[[str], Never]的错误。 - 最小复现案例中,MyPy同样无法确定
None应该对应S1还是F1,因此也会触发类型不匹配的报错。
解决方法
- 显式指定类型参数:给
n1添加类型注解,明确各个TypeVar对应的类型,比如:n1: Node[str, Succ1, Fail1] = Node(func1) - 合并TypeVar并添加约束:将
S1和F1合并为一个带约束的TypeVar,简化泛型定义:from typing import Generic, TypeVar, Callable, reveal_type I = TypeVar('I') Result = TypeVar('Result', Succ1, Fail1) class Node(Generic[I, Result]): def __init__(self, callback: Callable[[I], Result]): self.callback: Callable[[I], Result] = callback
内容的提问来源于stack exchange,提问作者Anka
相关产品推荐
相关产品推荐

