Mypy无法正确解析复合条件下的Union类型,求优化处理方案
解决mypy对复合条件下Union类型推导报错的问题
当mypy解析Union类型时,会通过代码流推导类型,如下代码可以正常通过mypy检查:
import typing as typ def foo(x: typ.Union[int, None] = None, y: typ.Union[int, None] = None) -> int: if x is None and y is None: raise ValueError if x is None: x = 1 if y is None: y = 2 return x + y foo(1, 2)
但当调整为复合条件(逻辑仍正确)时,mypy会报错:
import typing as typ def foo(x: typ.Union[int, None] = None, y: typ.Union[int, None] = None) -> int: if x is None and y is None: raise ValueError if x is None and y is not None: x = 1 if y is None and x is not None: y = 2 return x + y foo(1, 2)
报错信息:
main.py:15: error: Unsupported operand types for + ("int" and "None") main.py:15: error: Unsupported operand types for + ("None" and "int") main.py:15: error: Unsupported left operand type for + ("None") main.py:15: note: Both left and right operands are unions Found 3 errors in 1 file (checked 1 source file)
针对必须使用复合条件、不愿添加冗余代码的需求,以下是几种更优的处理方式:
1. 重构条件分支为互斥结构
将后续的if改为elif,让分支逻辑更清晰,帮助mypy完成类型推导:
import typing as typ def foo(x: typ.Union[int, None] = None, y: typ.Union[int, None] = None) -> int: if x is None and y is None: raise ValueError elif x is None: # 此时y必然不为None(已被前面的条件排除) x = 1 elif y is None: # 此时x必然不为None(已被前面的条件排除) y = 2 return x + y
这种方式无需额外代码,通过优化分支逻辑让mypy自然识别变量类型,是最推荐的方案。
2. 使用assert辅助类型推导
在return前添加assert语句,既可以辅助mypy推导类型,又能保留运行时的逻辑校验(并非冗余代码):
import typing as typ def foo(x: typ.Union[int, None] = None, y: typ.Union[int, None] = None) -> int: if x is None and y is None: raise ValueError if x is None and y is not None: x = 1 if y is None and x is not None: y = 2 # 断言x和y均不为None,帮助mypy推导类型 assert x is not None and y is not None, "x或y不能为None" return x + y
assert在运行时会触发检查,若逻辑出错能及时发现,同时mypy会将其视为类型断言,认定后续x和y均为int类型。
3. 使用typing.cast强制类型标注
通过cast直接告知mypy变量的实际类型,绕过类型推导限制:
import typing as typ def foo(x: typ.Union[int, None] = None, y: typ.Union[int, None] = None) -> int: if x is None and y is None: raise ValueError if x is None and y is not None: x = 1 if y is None and x is not None: y = 2 return typ.cast(int, x) + typ.cast(int, y)
注意:cast仅用于类型检查阶段,不会对实际运行时的变量做转换,因此必须确保逻辑上x和y此时确实不为None,否则会引发运行时错误。
内容的提问来源于stack exchange,提问作者norok2
相关产品推荐
相关产品推荐

