首页 > 解决方案 > Mypy 抱怨 __setitem__ 签名

问题描述

我有一个子类,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, index: Union[SupportsIndex, 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) 和一个slice对象作为它的第一个参数。几乎好像mypy以某种方式得出了仅int支持 -like 对象的结论 - 这与第二个错误相匹配,它只期望 aMyData作为第二个参数,而不是Iterable[MyData].

我在 Python 3.7 和 3.9 上都试过这个,错误是一样的。我当然可以告诉mypy忽略这些错误,但我真的很想知道是什么原因造成的,以及如何解决它。有任何想法吗?

标签: pythonmypy

解决方案


按照这个类似的问题。Mypy 不使用重载信息对函数体进行类型检查。

为了解决您的问题,您可以通过isinstance. 像这样:

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, index: Union[SupportsIndex, slice]) -> None:
        # Administrative stuff deleted
        super().__delitem__(index)

推荐阅读