要让自定义类支持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
使用示例:
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
这样无需单独定义迭代器类,yield 自动构建迭代器,状态自动保存,StopIteration 由解释器自动抛出。代码更短,不易出错,是 Python 中实现可迭代对象的首选方式。