问题描述
我有一个 list
的子类,它在列表的组件上添加了一些管理内容。一切正常,但 mypy
抱怨 super
调用 __setitem__
的签名。
这是问题减少到最低限度:
from typing import List,Iterable,Union,overload
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
super().__setitem__(index,value)
def __delitem__(self,slice]) -> None:
# Administrative stuff deleted
super().__delitem__(index)
当我运行 mypy
时,我得到:
src\seq.py:18: error: Invalid index type "Union[SupportsIndex,slice]" for "MyDataSeq"; expected type "SupportsIndex"
src\seq.py:18: error: Incompatible types in assignment (expression has type "Union[MyData,Iterable[MyData]]",target has type "MyData")
Found 2 errors in 1 file (checked 1 source file)
我在这里不知所措,因为显然 __setitem__
和 __delitem__
一样,同时接受 int
-like (SupportsIndex
) 和 {{1}对象作为它的第一个参数。几乎好像 slice
以某种方式得出了只支持 mypy
类对象的结论——这与第二个错误相匹配,即它只期望一个 int
作为第二个参数,而不是 { {1}}。
我在 Python 3.7 和 3.9 上都试过这个,错误是一样的。
我当然可以告诉 MyData
忽略这些错误,但我真的很想知道这是什么原因造成的,以及如何解决它。有什么想法吗?
解决方法
根据this类似的问题。 Mypy 不使用重载信息对函数体进行类型检查。
要解决您的问题,您可以通过 isinstance
向 Mypy give a hint 传递您传递给它的类型。像这样:
from typing import List,Iterable,Union,overload
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) and isinstance(value,Iterable):
super().__setitem__(index,value)
elif isinstance(index,int) and isinstance(value,MyData):
super().__setitem__(index,value)
else:
raise TypeError(f"{index}/{value} Invalid index/value type.")
def __delitem__(self,slice]) -> None:
# Administrative stuff deleted
super().__delitem__(index)
,
您不需要对实现进行注释,只需对修饰的定义进行注释。
class MyDataSeq(List[MyData]):
@overload
def __setitem__(self,value: MyData) -> None:
...
@overload
def __setitem__(self,value: Iterable[MyData]) -> None:
...
def __setitem__(self,index,value):
# Administrative stuff deleted
super().__setitem__(index,value)
def __delitem__(self,slice]) -> None:
# Administrative stuff deleted
super().__delitem__(index)
(这会给 __delitem__
留下一个类似的问题,但我认为这是一个单独的问题。)