Python内置序列对负数索引的支持由解释器预处理,自定义类需在__getitem__中手动转换:先取长度,若key为负则加长度,再检查边界;切片需用key.indices(len(self))标准化。

负数索引在 __getitem__ 中不自动处理
Python 内置序列(如 list、str)对负数索引(如 -1)的支持,是解释器在调用 __getitem__ 前就做好的转换:把 -1 变成 len(self) - 1,再传给你的方法。但自定义类不会自动做这事——你得自己判断并转换。
常见错误现象:my_seq[-1] 直接抛 IndexError,或者返回意外元素(比如把 -1 当成正向索引用了)。
关键点:不能假设传进来的 key 已经是合法正向索引;必须显式检查是否为负,并映射到对应正向位置。
正确实现 __getitem__ 支持负数索引的步骤
核心逻辑就是三步:获取长度 → 判断是否为负 → 转换后查表。注意边界检查要统一放在转换之后,避免重复或遗漏。
- 先调用
len(self)获取有效长度(确保你已实现__len__) - 若
key ,计算key += len(self);如果结果或>= len(self),直接 raiseIndexError - 否则按正常正向索引处理(比如查内部列表、字典或计算生成)
示例:
def __getitem__(self, key):
n = len(self)
if key <h3>切片(<code>slice</code>)对象也要单独处理</h3><p>用户写 <code>my_seq[-3:]</code> 或 <code>my_seq[1:-1]</code> 时,传进来的是 <code>slice</code> 实例,不是整数。不处理它,会直接报 <code>TypeError: 'slice' object cannot be interpreted as an integer</code>。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill9965" title="macOS UI 自动化技能包 —— 用 Python 控制你的 Mac"><img
src="https://img.php.cn/upload/skill/001/246/273/6adaf20dbae7c507.jpg" alt="macOS UI 自动化技能包 —— 用 Python 控制你的 Mac" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill9965" title="macOS UI 自动化技能包 —— 用 Python 控制你的 Mac" class="overflowclass">macOS UI 自动化技能包 —— 用 Python 控制你的 Mac</a>
<p class="overflowclass">让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript
系统要求
macOS 14+ (Sonoma)
Python 3.9+
需要开启:辅助功能 + 屏幕录制权限</p>
</div>
<a rel="nofollow" href="/xiazai/skill9965" title="macOS UI 自动化技能包 —— 用 Python 控制你的 Mac" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><p>你需要在 <code>__getitem__</code> 开头加类型判断:</p>
- 用
isinstance(key, slice)分支,调用key.indices(len(self))获取标准化后的(start, stop, step) -
indices()会自动把负数起止位置转成正向值,且处理越界(比如slice(-10, -1)在长度为 5 的序列上会被转成(0, 4, 1)) - 然后用这些值构造新切片或遍历生成结果
简例(返回子序列):
def __getitem__(self, key):
if isinstance(key, slice):
start, stop, step = key.indices(len(self))
return [self[i] for i in range(start, stop, step)]
# ... 后续处理 int key 的逻辑
容易被忽略的兼容性细节
负数索引支持看似简单,但几个细节常导致行为和内置类型不一致:
-
__len__必须返回非负整数;如果返回负数,key += len(self)会让负索引更负,彻底崩掉 - 空序列时
len(self) == 0,此时任何负索引(如-1)转换后仍是负数,必须明确拦截 - 如果底层存储不支持随机访问(比如是生成器或链表),别硬套
self._data[key]—— 要改用迭代或缓存策略 - 某些场景下你还得同步支持
__setitem__和__delitem__的负索引,逻辑要保持一致
最麻烦的其实是 slice + 负 step 的组合(如 [::-1]),indices() 能帮你兜底,但返回的 range 对象仍需你正确遍历——别想当然用 reversed(),因为 step 可能不是 -1。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










