Mypy对自定义list子类的__setitem__重载签名报错如何解决?
报错根本原因
mypy在处理重载方法的调用时,不会对Union类型的入参做自动的重载分支匹配,只会优先尝试匹配第一个重载定义。
你子类定义的__setitem__虽然有两个正确的重载分支,但是在调用super().__setitem__时,传入的index是Union[SupportsIndex, slice]类型,value是Union[MyData, Iterable[MyData]]类型,mypy会直接用这两个Union类型去匹配父类list的__setitem__的第一个重载:
def __setitem__(self, index: SupportsIndex, value: MyData) -> None
自然就会报「索引类型不匹配」「值类型不匹配」的错误。
而__delitem__没有重载,它的签名本身就接受Union[SupportsIndex, slice]类型的入参,所以传Union参数不会触发错误。
正确解决方法
最简单的无忽略实现是通过显式分支缩小参数类型,让mypy可以匹配到对应的重载分支:
from typing import List, Iterable, Union, overload, cast from typing_extensions import SupportsIndex class MyData: pass class MyDataSeq(List[MyData]): @overload def __setitem__(self, index: SupportsIndex, value: MyData) -> None: ... @overload def __setitem__(self, index: slice, value: Iterable[MyData]) -> None: ... def __setitem__(self, index: Union[SupportsIndex, slice], value: Union[MyData, Iterable[MyData]]) -> None: # Administrative stuff deleted if isinstance(index, slice): super().__setitem__(index, cast(Iterable[MyData], value)) else: super().__setitem__(index, cast(MyData, value)) def __delitem__(self, index: Union[SupportsIndex, slice]) -> None: # Administrative stuff deleted super().__delitem__(index)
这里的cast是零运行时代价的类型标注,用来告诉mypy当前分支下value的确定类型,符合你重载定义的参数对应规则,不会影响实际运行逻辑。
如果你接受局部忽略mypy错误,也可以直接在调用行加# type: ignore[arg-type],但显式分支的方案更符合类型安全要求,可维护性更高。
内容的提问来源于stack exchange,提问作者Ruud de Jong
相关产品推荐
相关产品推荐

