云计算百科
云计算领域专业知识百科平台

python3迭代器怎样自定义类

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 遍历机制的理解,还能写出更高效、更优雅的代码。希望这篇文章对你有所帮助。

赞(0)
未经允许不得转载:网硕互联帮助中心 » python3迭代器怎样自定义类
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!