1. 引言
在 Python 中,迭代器(Iterator)是一个非常基础且重要的概念。无论是 for 循环遍历列表、读取文件行,还是使用 zip、map 等内置函数,背后都离不开迭代器。Python 内置的列表、元组、字典、集合等数据类型都是可迭代对象(Iterable),但很多时候,我们需要自定义一个类,让它具备迭代能力,从而更灵活地控制遍历逻辑。
本文将借鉴一篇关于 Python 迭代器的经典教程,结合 Python3 的语法特性,详细介绍如何自定义一个迭代器类,包括核心概念、实现方法、常见应用场景以及注意事项。
2. 迭代器与可迭代对象
在动手写代码之前,先厘清两个容易混淆的概念:可迭代对象(Iterable)和迭代器(Iterator)。
2.1 可迭代对象(Iterable)
可迭代对象是指实现了 __iter__() 方法的对象,它返回一个迭代器。简单来说,凡是可以用 for 循环遍历的对象,都是可迭代对象。例如:
lst = [1, 2, 3]
for x in lst:
print(x)
这里的 lst 就是一个可迭代对象。
2.2 迭代器(Iterator)
迭代器是实现了 __iter__() 和 __next__() 两个方法的对象。其中:
- __iter__() 返回迭代器自身;
- __next__() 返回下一个元素,当没有更多元素时抛出 StopIteration 异常。
迭代器是一个「一次性」对象,遍历结束后不能再从头开始。
2.3 两者的关系
可以用一句话概括:可迭代对象通过 iter() 函数得到迭代器,迭代器通过 next() 函数逐个取值。
lst = [1, 2, 3]
it = iter(lst) # 获取迭代器
print(next(it)) # 1
print(next(it)) # 2
print(next(it)) # 3
print(next(it)) # 抛出 StopIteration
3. 自定义迭代器类的基本结构
自定义一个迭代器类,核心就是实现 __iter__() 和 __next__() 两个方法。下面我们从一个最简单的例子开始。
3.1 最简单的自定义迭代器
假设我们要实现一个「从 0 数到 n-1」的计数器:
class Counter:
"""一个简单的计数器迭代器,从 0 数到 n-1"""
def __init__(self, n):
self.n = n
self.current = 0
def __iter__(self):
return self
def __next__(self):
if self.current < self.n:
value = self.current
self.current += 1
return value
else:
raise StopIteration
使用方式:
for i in Counter(5):
print(i)
# 输出:0 1 2 3 4
3.2 代码解析
- __init__:初始化迭代的起始状态,这里用 self.current 记录当前计数位置。
- __iter__:返回 self,表示迭代器本身也是可迭代对象。
- __next__:每次调用返回下一个值;当计数达到上限时抛出 StopIteration,for 循环会捕获该异常并自动结束。
4. 让自定义类同时支持迭代与索引
有时候,我们希望一个类既能用 for 遍历,又能像列表一样通过下标访问。这时可以让类实现 __iter__ 和 __getitem__ 两个方法。
class MyList:
def __init__(self, data):
self.data = data
def __getitem__(self, index):
return self.data[index]
def __iter__(self):
return iter(self.data)
这样,MyList 既支持 for x in obj,也支持 obj[0] 这样的下标访问。
5. 实战案例:自定义一个斐波那契迭代器
斐波那契数列是学习迭代器时最经典的例子。用迭代器实现,可以做到「按需生成」,避免一次性占用大量内存。
class Fibonacci:
"""斐波那契数列迭代器,生成前 n 项"""
def __init__(self, n):
self.n = n
self.count = 0
self.a, self.b = 0, 1
def __iter__(self):
return self
def __next__(self):
if self.count < self.n:
result = self.a
self.a, self.b = self.b, self.a + self.b
self.count += 1
return result
else:
raise StopIteration
使用:
for num in Fibonacci(10):
print(num, end=" ")
# 输出:0 1 1 2 3 5 8 13 21 34
6. 使用生成器简化迭代器
Python 提供了一种更简洁的写法——生成器(Generator)。生成器本质上就是迭代器,但不需要手动实现 __iter__ 和 __next__,只需使用 yield 关键字。
def fibonacci_gen(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
上面的生成器函数与前面的 Fibonacci 类功能完全一致,但代码量大大减少。在大多数场景下,优先推荐使用生成器;只有当需要维护复杂状态或复用迭代逻辑时,才考虑自定义迭代器类。
7. 迭代器的常见应用场景
自定义迭代器类在实际开发中有很多用途,这里列举几个典型场景:
7.1 大数据流式处理
当数据量很大、无法一次性载入内存时,可以用迭代器逐条读取和处理。例如自定义一个逐行读取大文件的迭代器:
class FileReader:
def __init__(self, filepath):
self.filepath = filepath
def __iter__(self):
with open(self.filepath, "r", encoding="utf-8") as f:
for line in f:
yield line.strip()
7.2 无限序列
迭代器天然适合表示无限序列,因为它是惰性求值的,只有调用 next() 时才计算下一个值。
class NaturalNumbers:
"""自然数迭代器,无限生成"""
def __iter__(self):
n = 1
while True:
yield n
n += 1
使用时配合 itertools.islice 截取前若干项:
from itertools import islice
nums = NaturalNumbers()
for x in islice(nums, 5):
print(x) # 1 2 3 4 5
7.3 自定义遍历顺序
迭代器可以完全控制遍历顺序,例如实现一个「倒序遍历」的迭代器:
class ReverseList:
def __init__(self, data):
self.data = data
self.index = len(data) – 1
def __iter__(self):
return self
def __next__(self):
if self.index >= 0:
value = self.data[self.index]
self.index -= 1
return value
else:
raise StopIteration
8. 注意事项与常见坑
8.1 迭代器是一次性的
迭代器遍历结束后,无法重新从头开始。如果需要重复遍历,应重新创建迭代器对象。
it = iter([1, 2, 3])
list(it) # [1, 2, 3]
list(it) # [],已经耗尽
8.2 __iter__ 返回 self 的约定
如果类本身是迭代器,__iter__ 应返回 self。如果类只是可迭代对象(内部持有迭代器),则 __iter__ 应返回一个新的迭代器。
8.3 不要忘记抛出 StopIteration
__next__ 在元素耗尽时必须抛出 StopIteration,否则 for 循环会无限执行下去。
8.4 优先考虑生成器
除非需要复杂的类状态管理,否则优先使用生成器函数,代码更简洁、可读性更高。
9. 总结
本文从迭代器与可迭代对象的基本概念出发,详细介绍了如何在 Python3 中自定义一个迭代器类,包括核心方法 __iter__ 和 __next__ 的实现、实战案例(斐波那契数列)、生成器的简化写法,以及迭代器在流式处理、无限序列等场景中的应用。
掌握自定义迭代器,不仅能加深对 Python 遍历机制的理解,还能写出更高效、更优雅的代码。希望这篇文章对你有所帮助。
网硕互联帮助中心




评论前必须登录!
注册