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

如何正确继承tuple类并实现索引切片,满足mypy检查?

解决继承tuple[int, ...]时的__getitem__重载问题

首先明确:你确实误用了singledispatchmethod——这个装饰器不适合用来重载特殊方法(比如__getitem__),尤其是在需要通过mypy类型检查的场景下,它会导致类型签名冲突,也就是你遇到的“__getitem__重复定义”错误。

正确实现方案

我们需要用@overload来明确两种__getitem__的类型签名,同时手动处理索引和切片的返回逻辑,确保切片返回MyIntTuple实例而非原生tuple。

完整代码示例:

from typing import overload, Self, Tuple

class MyIntTuple(tuple[int, ...]):
    @overload
    def __getitem__(self, key: int) -> int: ...

    @overload
    def __getitem__(self, key: slice) -> Self: ...

    def __getitem__(self, key: int | slice) -> int | Self:
        # 处理索引情况
        if isinstance(key, int):
            return super().__getitem__(key)
        # 处理切片情况:先获取原生tuple切片结果,再包装成MyIntTuple
        sliced_tuple = super().__getitem__(key)
        return MyIntTuple(sliced_tuple)

    # 可选:定义__new__确保实例创建符合类型要求
    @classmethod
    def __new__(cls, iterable: Tuple[int, ...]) -> Self:
        return super().__new__(cls, iterable)

关键说明

  1. @overload的作用:

    • 给mypy明确两种调用场景的类型签名:传入int索引返回int,传入slice返回MyIntTuple实例。
    • 避免了重复定义的错误,因为mypy会识别这些重载是同一方法的不同类型分支。
  2. 切片返回自定义实例:

    • 调用父类的__getitem__拿到切片后的原生tuple,再用MyIntTuple包装返回,这样就实现了切片返回自定义类型的需求。
  3. 为什么不用singledispatchmethod:

    • singledispatchmethod是基于函数参数的类型分发,但特殊方法的调用逻辑(比如obj[key])会绕过它的分发机制,导致实际运行时可能不符合预期。
    • mypy对singledispatchmethod修饰的特殊方法类型推断支持不佳,容易触发重复定义的错误提示。

测试验证

运行以下代码,同时用mypy检查:

t = MyIntTuple((1, 2, 3, 4))
print(t[0])          # 输出1,类型为int
print(t[1:3])        # 输出MyIntTuple((2, 3)),类型为MyIntTuple
print(type(t[1:3]))  # 输出<class '__main__.MyIntTuple'>

mypy不会再提示重复定义错误,且能正确推断返回值类型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 22:10:06