Python拼接不同类型列表触发MyPy报错如何无需抑制即可解决
问题原因
MyPy进行列表拼接的类型推断时,会优先以最左侧列表的类型作为整个表达式的基准类型。你写的[A1]会被默认推断为List[Type[A1]],而列表是不变型容器,不允许自动向上转型到更宽的List[Union[Sequence[Type[A]], Type[A]]]类型,后续拼接Type[A2]和嵌套列表的时候就会触发类型不匹配错误。手动直接构造完整列表时,MyPy会扫描所有元素来推断类型,所以不会出现这个问题。
解决方案
方案1:显式标注临时变量的类型
提前声明拼接结果的类型,让MyPy按照指定的宽类型做校验,不会自动窄化,该方案无运行时代价,也不需要修改原有类型定义:
#!/usr/bin/python3 from typing import Union, List, NewType, Type, Sequence class A: pass class A1(A): pass class A2(A): pass B = NewType("B", Sequence[Union[Sequence[Type[A]], Type[A]]]) # 显式标注临时变量的目标类型 temp: Sequence[Union[Sequence[Type[A]], Type[A]]] = [A1] + [A2]*2 + [[A1, A2]] b1 = B(temp) b2 = B([A1, A2, [A1, A2]])
方案2:显式转换首个列表的类型
如果不想单独声明临时变量,可以用typing.cast直接指定最左侧列表的类型,打断MyPy的自动窄化推断:
from typing import cast b1 = B(cast(list[Union[Sequence[Type[A]], Type[A]]], [A1]) + [A2]*2 + [[A1, A2]])
方案3:先创建空列表再逐个添加元素
空列表默认会根据后续添加的元素推断更宽的类型,也可以规避列表拼接的类型推断问题:
temp = [] temp.append(A1) temp.extend([A2]*2) temp.append([A1, A2]) b1 = B(temp)
以上三种方案都不需要添加# type: ignore抑制MyPy校验,完全符合类型规范。
内容的提问来源于stack exchange,提问作者Hait
相关产品推荐
相关产品推荐

