You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实现MutableSequence时__setitem__调用重载函数报mypy类型不兼容错误

问题解决

错误核心原因

mypy不会在重载函数的实现逻辑中自动推导不同参数之间的绑定关系,你声明的__setitem__重载规则只对外部调用生效,在实现函数内部,mypy只会将参数识别为独立的联合类型:unsafe_index: SupportsIndex | slice、value: T | Iterable[T],不知道二者的类型是一一绑定的,因此抛出三个关联错误。
三个错误的具体诱因:

  • 第34行错误:mypy无法确认实现函数的参数组合覆盖了所有重载声明的合法组合,担心出现索引 + 可迭代对象、切片 + 单个值的非法调用。
  • 第38行第一个错误:_normalise_index返回值是slice | int的联合类型,mypy不知道当前场景应该匹配列表的索引还是切片语法。
  • 第38行第二个错误:value是T | Iterable[T]的联合类型,mypy不知道应该匹配列表单个位置赋值还是切片赋值的类型要求。

修复方案

在__setitem__实现内部对索引类型做显式窄化,配合cast标注对应分支的value类型即可解决所有错误,重载规则本身没有问题。
修复后的完整代码:

from typing import Iterable, SupportsIndex, TypeVar, overload, cast

T = TypeVar("T")


class Example:
    def __init__(self, iterable: Iterable[T]):
        self._lst = list(iterable)

    def __len__(self) -> int:
        return len(self._lst)

    @overload
    def _normalise_index(self, index: slice) -> slice: ...
    @overload
    def _normalise_index(self, index: SupportsIndex) -> int: ...

    def _normalise_index(self, index: slice | SupportsIndex) -> slice | int:
        "将负索引转换为正索引,实际业务场景下该逻辑合理"
        if isinstance(index, slice):
            return slice(
                0 if not index.start else self._normalise_index(index.start),
                len(self) if not index.stop else self._normalise_index(index.stop),
                index.step or 1,
            )
        else:
            return len(self) + idx if (idx := int(index)) < 0 else idx

    @overload
    def __setitem__(self, unsafe_index: SupportsIndex, value: T) -> None: ...
    @overload
    def __setitem__(self, unsafe_index: slice, value: Iterable[T]) -> None: ...

    def __setitem__(
        self, unsafe_index: SupportsIndex | slice, value: T | Iterable[T]
    ) -> None:
        if isinstance(unsafe_index, slice):
            # 窄化后mypy可推导出_normalise_index返回slice
            normalised_index = self._normalise_index(unsafe_index)
            # 重载已保证切片场景下value为Iterable[T],cast无运行时开销
            self._lst[normalised_index] = cast(Iterable[T], value)
        else:
            # 窄化后mypy可推导出_normalise_index返回int
            normalised_index = self._normalise_index(unsafe_index)
            # 重载已保证索引场景下value为T
            self._lst[normalised_index] = cast(T, value)

说明

如果不想用cast,也可以在分支内添加运行时类型检查,但要注意str、bytes等本身也是可迭代类型,容易对T为字符串的场景造成误判,因此使用cast是更高效的方案。

内容的提问来源于stack exchange,提问作者Greedo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 18:15:05