Python序列协议教程_自定义可迭代对象

14次阅读

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

Python序列协议教程_自定义可迭代对象

要让自定义类支持 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 中实现可迭代对象的首选方式。

text=ZqhQzanResources