__getitem__ 方法使实例支持方括号取值,触发于索引、切片及 in 操作(未定义 __contains__ 时),参数 key 类型自定义,需主动抛出 IndexError 或 KeyError,切片传入 slice 对象,负索引需手动处理,典型实现需分支判断 int 和 slice 并返回同类型结果。

__getitem__ 方法的基本写法和触发条件
只要在类里定义了 __getitem__,实例就能用方括号取值,比如 obj[0] 或 obj['key']。它不依赖 __iter__ 或长度信息,Python 在遇到索引、切片、in 操作(当没定义 __contains__ 时)都会调用它。
注意:参数 key 是你写在方括号里的东西,类型完全由你决定——可以是 int、str、slice,甚至自定义对象。
- 如果
key类型非法或超出范围,应主动抛出IndexError或KeyError,别让 Python 报TypeError: 'xxx' object is not subscriptable - 切片传进来的是
slice对象,不是元组,别用key[0]去拆 - 支持负索引需自行处理,Python 不会自动转换
支持整数索引和切片的典型实现
多数容器类(如模拟 list)需要处理 int 和 slice 两种 key。关键在于识别 isinstance(key, slice),并返回同类型结果(切片返回新实例或子列表)。
class MyList:
def __init__(self, data):
self._data = list(data)
<pre class="brush:php;toolbar:false;">def __getitem__(self, key):
if isinstance(key, int):
# 处理负索引
if key <p></p>
- 返回
MyList而非list,才能继续用[...][...] - 没做
step != 1的特殊优化,但self._data[key]本身已支持 - 没实现
__len__不影响索引,但len(obj)会失败
支持字符串键的字典式访问
想让类像 dict 一样用 obj['name'],__getitem__ 直接查内部字典或属性即可,但要注意错误类型:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- 查不到该 key 应抛
KeyError,不是IndexError - 若同时支持数字索引和字符串键,需在方法内分支判断
isinstance(key, (int, str))等 - 避免把所有属性都暴露出去——显式维护一个
_mapping字典比用getattr(self, key)更安全
示例片段:
def __getitem__(self, key):
if isinstance(key, str):
if key not in self._fields:
raise KeyError(f"no field named '{key}'")
return getattr(self, key)
elif isinstance(key, int):
return self._data[key] # 同前
else:
raise TypeError(...)
容易被忽略的兼容性细节
很多初学者以为写了 __getitem__ 就万事大吉,实际几个隐性坑常导致行为异常:
-
for x in obj:会先尝试__iter__,失败才回退到__getitem__(从 0 开始调用直到IndexError),所以没有__iter__时循环性能差且不支持break早停 -
obj[1:3]若返回普通list,后续就不能再索引(obj[1:3][0]可以,但obj[1:3].append(...)会报错) - NumPy 或 pandas 的数组协议(
__array__)可能绕过__getitem__,调试时注意实际调用栈
真正要用好,得配合 __len__、__iter__、__contains__ 一起设计,单点补丁容易翻车。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










