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

如何在Python自定义类中实现MutableSequence并使用@overload装饰器

实现说明

首先明确:Python 标准库的 @overload 装饰器仅用于类型标注,不会提供运行时的方法重载能力,它的作用是给类型检查工具(比如PyCharm、mypy)声明方法在不同入参下对应的返回值类型,运行时实际只会调用最后你实现的那个不带@overload的同名方法。
你只需要按照以下逻辑实现即可:

  1. 保留PyCharm生成的所有@overload签名,删掉签名上的@abstractmethod装饰器(否则类会被识别为抽象类无法实例化)
  2. 最后实现的通用方法里,自行判断参数类型(整数/切片)执行对应逻辑即可

完整可运行示例
from collections.abc import MutableSequence, Iterable
from typing import TypeVar, overload

T = TypeVar('T')

class Test(MutableSequence[T]):
    # 构造函数,这里用内部列表存储实际数据,你可以替换为自己的存储逻辑
    def __init__(self, data: Iterable[T] = ()):
        self._data = list(data)

    def insert(self, index: int, object: T) -> None:
        self._data.insert(index, object)

    # __getitem__的两个重载签名,仅做类型标注用
    @overload
    def __getitem__(self, i: int) -> T: ...

    @overload
    def __getitem__(self, s: slice) -> MutableSequence[T]: ...

    # 实际运行时调用的实现
    def __getitem__(self, item: int | slice) -> T | MutableSequence[T]:
        if isinstance(item, int):
            return self._data[item]
        elif isinstance(item, slice):
            # 切片返回同类型实例,符合MutableSequence的行为预期
            return Test(self._data[item])
        raise TypeError(f"索引类型只能是int或slice,当前为{type(item)}")

    # __setitem__的两个重载签名
    @overload
    def __setitem__(self, i: int, o: T) -> None: ...

    @overload
    def __setitem__(self, s: slice, o: Iterable[T]) -> None: ...

    def __setitem__(self, key: int | slice, value: T | Iterable[T]) -> None:
        if isinstance(key, int):
            self._data[key] = value # type: ignore
        elif isinstance(key, slice):
            if not isinstance(value, Iterable):
                raise TypeError("切片赋值需要传入可迭代对象")
            self._data[key] = value
        else:
            raise TypeError(f"索引类型只能是int或slice,当前为{type(key)}")

    # __delitem__的两个重载签名
    @overload
    def __delitem__(self, i: int) -> None: ...

    @overload
    def __delitem__(self, i: slice) -> None: ...

    def __delitem__(self, key: int | slice) -> None:
        self._data.__delitem__(key)

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

    # 可选:实现__repr__方便调试
    def __repr__(self):
        return f"Test({self._data})"

# 使用测试
if __name__ == "__main__":
    t = Test([1,2,3,4,5])
    print(t[0]) # 输出1,整数索引取单个值
    print(t[1:4]) # 输出Test([2,3,4]),切片返回同类型实例
    t[0] = 10
    print(t) # 输出Test([10,2,3,4,5])
    t[1:3] = [20,30]
    print(t) # 输出Test([10,20,30,4,5])
    del t[0]
    print(t) # 输出Test([20,30,4,5])
    del t[1:]
    print(t) # 输出Test([20])

注意事项
  • 所有带@overload的方法不需要写实现,仅保留签名即可
  • 实际实现的方法需要覆盖所有重载的参数场景,内部通过isinstance判断参数类型走不同分支
  • PyCharm会基于你写的@overload签名做代码提示,比如整数索引取值会提示返回单个元素,切片取值会提示返回序列,赋值时也会做对应的类型校验

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 02:18:01