要让自定义类支持for循环等操作,关键在于实现迭代协议:提供返回迭代器的__iter__()方法,且该迭代器实现__next__()方法;生成器函数是更简洁安全的首选方式。

要让自定义类支持 for 循环、list()、tuple() 等操作,关键不是实现某个“序列协议”,而是正确实现 迭代协议(Iterator Protocol)——即提供 __iter__() 方法,返回一个迭代器对象;该迭代器对象需实现 __next__() 方法,按需产出元素。
什么是迭代协议?
Python 的 迭代协议 是语言层面的约定:只要一个对象实现了 __iter__() 方法,且该方法返回一个带有 __next__() 方法的对象,它就被视为可迭代对象(iterable)。这和“序列协议”(要求支持索引、长度、切片等)不同——你不需要继承 list 或实现 __getitem__ 才能被 for 遍历。
-
for x in obj:会自动调用obj.__iter__() - 返回的迭代器对象每次调用
__next__()返回下一个值,直到抛出StopIteration -
iter(obj)和next(it)是对这两个方法的内置封装
如何写一个最简可迭代类?
下面是一个只支持正向遍历、不支持索引或长度的轻量级可迭代类:
class Countdown:
def __init__(self, start):
self.start = start
def __iter__(self):
# 每次调用 iter() 都返回一个新迭代器(避免重复遍历失效)
return CountdownIterator(self.start)class CountdownIterator:
def init(self, start):
self.current = start
def __next__(self):
if self.current <= 0:
raise StopIteration
value = self.current
self.current -= 1
return value
def __iter__(self):
# 迭代器自身也是可迭代的(符合惯例)
return self
立即学习“Python免费学习笔记(深入)”;
使用示例:
for i in Countdown(3):
print(i) # 输出:3, 2, 1
list(Countdown(3)) # [3, 2, 1]
常见误区与注意事项
很多初学者容易混淆几个概念,导致行为异常:
-
错误:在
__iter__中直接返回self且没实现__next__→ 报TypeError: iter() returned non-iterator -
错误:
__iter__返回同一个迭代器实例多次 → 第二次for循环将为空(因为迭代器已耗尽) -
混淆序列与迭代器:实现
__getitem__(从 0 开始连续整数索引)也能让对象被for遍历,但这是回退机制,不是推荐做法;且不支持len()或切片,除非额外实现 - 若希望同时支持
len()、索引、切片,应考虑继承collections.abc.Sequence并实现__len__、__getitem__,而非仅靠迭代协议
进阶:用生成器简化迭代器
绝大多数情况下,用生成器函数替代手动写迭代器类更简洁、安全:
class Countdown:
def __init__(self, start):
self.start = start
def __iter__(self):
n = self.start
while n > 0:
yield n
n -= 1
立即学习“Python免费学习笔记(深入)”;
这样无需单独定义迭代器类,yield 自动构建迭代器,状态自动保存,StopIteration 由解释器自动抛出。代码更短,不易出错,是 Python 中实现可迭代对象的首选方式。










