__getitem__必须显式返回可索引对象,否则隐式返回none导致typeerror;需处理int和slice两种key类型,切片应返回同类型新实例;越界必须抛indexerror。

能,但必须返回具体值,不能只写逻辑不返回;否则调用 obj[0] 会报 TypeError: 'NoneType' object is not subscriptable。
__getitem__ 必须有 return,且返回值要能被索引操作消费
很多人写完 __getitem__ 只打印日志或做校验,忘了 return。Python 解释器在执行 obj[i] 时,会强制要求该方法返回一个对象——哪怕返回 None,只要没 return,实际就是隐式返回 None,而 None 不支持后续索引(比如 obj[0][1]),就会立刻崩。
- 正确写法:必须显式
return一个支持索引的对象(如list、str、另一个自定义容器等)或标量(如int、str) - 错误典型:
def __getitem__(self, key): print(f"get {key}") # 缺少 return → 隐式 return None - 调试技巧:在方法末尾加一句
assert result is not None, "missing return",尤其在封装底层数据结构时
支持切片的关键是识别 slice 对象并返回新实例
当用户写 obj[1:4],传给 __getitem__ 的 key 是一个 slice 实例,不是整数。如果只处理 int 类型的 key,遇到切片就会抛 TypeError 或逻辑错乱。
- 判断方式:
isinstance(key, slice) - 返回什么:通常应返回同类型的新实例(如
MyList(self._data[key])),而不是原地修改或返回list——否则丢失自定义行为 - 注意边界:
slice.indices(len(self))可帮你把负索引、None起止值转成明确的(start, stop, step),避免手动算错
下标越界时抛 IndexError,别用 KeyError 或其他异常
Python 官方约定:容器类对无效索引应抛 IndexError,这是 for 循环、enumerate 等内置机制依赖的信号。抛 KeyError 或静默忽略,会导致迭代中断或行为不一致。
- 常见陷阱:用字典模拟列表时,直接
return self._dict[key],但字典缺 key 抛KeyError,不符合序列协议 - 正确做法:
if not (0 - 切片越界不用主动检查:
list对切片越界是宽容的([10:100]返回空列表),你的实现也应保持一致
最常被忽略的是:__getitem__ 不负责实现长度检查——len() 调用的是 __len__,而 for 循环先查 len 再逐个索引。如果你没实现 __len__,但又希望支持 for x in obj:,Python 会退回到用 __getitem__ 从 0 开始试,直到抛 IndexError 才停——这很慢,且无法预知循环次数。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











