__reversed__方法必须返回迭代器对象,而非列表或元组;它仅在显式调用reversed(obj)时触发,不影响for循环或切片;未实现时python会尝试通过__len__和__getitem__回退,但存在风险与性能问题。

__reversed__ 方法必须返回迭代器对象
Python 的 __reversed__ 不是让你直接 return 一个 list 或 tuple,它要求返回一个**迭代器**(iterator),否则 reversed(obj) 会抛出 TypeError: 'X' object is not reversible。常见错误是写成 return self.data[::-1]——这返回的是 list,不是迭代器。
正确做法是用 reversed() 包装可迭代对象,或手动 yield:
def __reversed__(self):
return reversed(self.data) # ✅ self.data 是 list/tuple 等内置可迭代类型
# 或
def __reversed__(self):
return iter(self.data[::-1]) # ✅ 转为迭代器
# 或用生成器(更省内存)
def __reversed__(self):
for i in range(len(self.data) - 1, -1, -1):
yield self.data[i]
__reversed__ 只在显式调用 reversed() 时触发
这个方法不会影响 for x in obj: 的行为,也不会被切片 obj[::-1] 调用。它只在你明确写 reversed(obj) 时才生效。如果你希望 for 循环也逆序,得自己控制逻辑,比如暴露一个 reverse_iter() 方法。
-
for x in reversed(my_obj):→ 触发__reversed__ -
for x in my_obj:→ 触发__iter__,与__reversed__无关 -
my_obj[::-1]→ 触发__getitem__和__len__(如果支持切片)
不实现 __reversed__ 时的 fallback 行为
如果你没定义 __reversed__,但类实现了 __len__ 和 __getitem__,Python 会尝试用索引倒序访问(即从 len-1 到 0)。但这有风险:
- 如果
__getitem__不支持整数索引(比如只支持 key 名),就会报TypeError - 如果
__len__返回 0 或负数,reversed()会静默失败或行为异常 - 性能差:每次取元素都要调用
__getitem__,不如直接返回预构造的反向迭代器
所以,哪怕只是简单封装,也建议显式实现 __reversed__,避免隐式 fallback 带来的不确定性。
自定义容器类中注意数据一致性
如果类内部数据可变(比如支持 append()、pop()),要注意 __reversed__ 返回的迭代器是否反映“当前”状态。例如:
class Stack:
def __init__(self):
self.items = []
def push(self, x): self.items.append(x)
def __reversed__(self):
return reversed(self.items) # ✅ 每次调用都基于当前 items
别写成在 __init__ 里缓存 self._rev_iter = reversed(...) ——那迭代器只生成一次,后续数据变更不会体现。
另外,如果类本身不打算支持逆序(比如流式 reader、单向链表),就不要实现 __reversed__,也不要依赖 fallback;显式抛出 NotImplementedError 更清晰。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











