如何为collections.abc.Sequence的最小实现正确添加__getitem__方法的类型提示?
如何为collections.abc.Sequence的最小实现正确添加__getitem__方法的类型提示?
刚好我之前也踩过这个类型提示的坑,咱们一步步来理清楚问题出在哪,怎么解决:
你的核心问题是:Sequence 要求 __getitem__ 既要支持整数索引,也要支持切片(slice)操作,不同的入参类型对应不同的返回值类型——而你的原代码只考虑了整数索引的情况,所以类型检查器会报错。
1. 基础版:用Union解决类型不兼容问题
首先,key 的类型不能只写 int,必须覆盖「整数」和「切片」两种场景,所以用 Union[int, slice] 标注。返回类型也要对应两种情况:整数索引返回单个 float,切片返回子序列(Sequence[float]),所以用 Union[float, Sequence[float]]。
修正后的基础版代码如下:
from collections.abc import Sequence from typing import override, Union class MySeq(Sequence[float]): def __init__(self): self._data: list[float] = list() @override def __len__(self) -> int: return len(self._data) @override def __getitem__(self, key: Union[int, slice]) -> Union[float, Sequence[float]]: result = self._data[key] # 切片返回的是list,最好包装成自定义的MySeq实例,严格符合Sequence规范 if isinstance(result, list): sub_seq = MySeq() sub_seq._data = result return sub_seq return result
2. 进阶版:用@overload实现精确类型推断
如果想要类型检查器能更精准地识别不同调用场景的返回类型(比如知道整数索引返回float,切片返回MySeq),可以用@overload分别标注两种情况:
from collections.abc import Sequence from typing import override, overload, Union class MySeq(Sequence[float]): def __init__(self): self._data: list[float] = list() @override def __len__(self) -> int: return len(self._data) @overload def __getitem__(self, key: int) -> float: ... @overload def __getitem__(self, key: slice) -> 'MySeq': ... @override def __getitem__(self, key: Union[int, slice]) -> Union[float, 'MySeq']: result = self._data[key] if isinstance(result, list): sub_seq = MySeq() sub_seq._data = result return sub_seq return result
用@overload之后,当你在代码里写my_seq[0],类型检查器会明确知道返回的是float;写my_seq[1:3]时,会知道返回的是MySeq,提示更精准。
为什么你的原代码会报错?
- 关于
key的警告:类型检查器知道Sequence规范要求支持切片操作,只写int不符合接口约定,所以会提示「slice不能赋值给int」。 - 关于返回类型的警告:当传入切片时,
self._data[key]返回的是list[float],但你标注的返回类型是float,类型完全不匹配,所以检查器会报错提示返回类型不兼容。
备注:内容来源于stack exchange,提问作者502E532E
相关产品推荐
相关产品推荐

