ZetCode

Python 无限迭代器

最后修改于 2025 年 3 月 29 日

本详细指南深入探讨了 Python 的无限迭代器,它们是能够无休止地生成值而不会触发 StopIteration 异常的特殊对象。我们将探讨内置的 itertools 模块函数,并通过清晰、实用的示例演示自定义实现。

理解无限迭代器

无限迭代器是唯一的对象,在迭代时会无限地产生值。与耗尽其元素后停止的有限迭代器不同,无限迭代器会持续产生值,直到手动停止。

basic_infinite.py
def count_up():
    n = 0
    while True:
        yield n
        n += 1

counter = count_up()
print(next(counter))  # 0
print(next(counter))  # 1
# Continues infinitely

count_up 生成器函数例证了无限迭代器的本质。它首先初始化变量 n 为零,使用 while True 进入无限循环,产生 n 的当前值,然后递增它以进行下一轮。每次调用 next 都会从 yield 点恢复函数,在无尽的序列中传递后续整数。这种模式是所有无限迭代器的基础。

itertools.count

itertools.count 函数生成一个无限生成连续数字的迭代器,为手动实现提供了强大的替代方案。

itertools_count.py
from itertools import count

# Basic count starting from 0
counter = count()
print(next(counter))  # 0
print(next(counter))  # 1

# Count with custom start and step
decimal_counter = count(start=1.0, step=0.25)
print(next(decimal_counter))  # 1.0
print(next(decimal_counter))  # 1.25

itertools.count 函数超越了我们的基本示例,它接受可选的 startstep 参数,支持整数和浮点数,利用 C 语言的效率,并确保准确的浮点数计算。它适用于生成唯一 ID、生成数字序列、计时重试尝试或制作测试数据等任务。

itertools.cycle

itertools.cycle 函数创建一个迭代器,该迭代器无限地重复有限可迭代对象中的元素,在到达末尾后又从头开始循环。

itertools_cycle.py
from itertools import cycle

seasons = cycle(['spring', 'summer', 'fall', 'winter'])
print(next(seasons))  # spring
print(next(seasons))  # summer
print(next(seasons))  # fall
print(next(seasons))  # winter
print(next(seasons))  # spring

此迭代器通过接受列表或元组等可迭代对象,将其元素存储在缓冲区中,依次产生它们,并在完成后从头开始。对于大型可迭代对象,它保持内存效率,支持任何可迭代对象类型,并准确地保留原始顺序。

itertools.repeat

itertools.repeat 函数生成一个迭代器,该迭代器根据其配置,无限地或在指定次数的迭代中产生一个值。

itertools_repeat.py
from itertools import repeat

# Infinite repetition
greeting = repeat('hello')
print(next(greeting))  # hello
print(next(greeting))  # hello

# Finite repetition
three_hi = repeat('hi', 3)
print(list(three_hi))  # ['hi', 'hi', 'hi']

repeat 函数提供两种模式:无限重复,默认情况下它会永远产生一个值;有限重复,当提供 times 参数时,它会产生该值一定的次数。它在创建常量流、填充序列、生成占位符数据或在映射中提供默认值方面表现出色。

自定义无限迭代器类

您可以通过实现 Python 的迭代器协议来设计自定义无限迭代器,从而根据特定需求定制行为。

custom_iterator.py
class Squares:
    def __iter__(self):
        self.n = 1
        return self
    
    def __next__(self):
        result = self.n * self.n
        self.n += 1
        return result

squares = Squares()
sq_iter = iter(squares)
print(next(sq_iter))  # 1
print(next(sq_iter))  # 4
print(next(sq_iter))  # 9
print(next(sq_iter))  # 16

Squares 类定义了一个生成平方数的迭代器,通过实现 __iter__ 来设置初始状态,并实现 __next__ 来计算每个后续的平方数。它将状态存储在实例变量中,并支持 for 循环和 next 调用。这种方法比生成器提供了更大的控制力,能够进行复杂的初始化、添加其他方法或与类的其他功能集成。

无限随机数据生成器

无限迭代器在生成连续的随机数据流方面表现出色,非常适合测试或模拟场景。

random_data.py
import random
import itertools

def random_chars():
    while True:
        yield chr(random.randint(65, 90))

# Create infinite random character stream
chars = random_chars()

# Take 5 samples
first_five = itertools.islice(chars, 5)
print(list(first_five))  # e.g., ['K', 'P', 'M', 'T', 'B']

本示例包含一个生成随机大写字母的无限生成器,并与 itertools.islice 配对以提取有限子集,然后将其转换为列表。此类迭代器对于负载测试、数据集生成、模拟实时输入或随机采样过程非常有用。

链接无限迭代器

itertools.chain 函数将多个迭代器(包括无限迭代器)链接成一个单一的无缝序列。

chaining_iterators.py
from itertools import chain, count, repeat

# Chain multiple iterators
combo = chain(
    count(5, 5),      # 5, 10, 15...
    repeat('X', 2),   # X, X
    count(50, -10)    # 50, 40, 30...
)

print(next(combo))  # 5
print(next(combo))  # 10
print(next(combo))  # 15
print(next(combo))  # X
print(next(combo))  # X
print(next(combo))  # 50

chain 函数会产生第一个迭代器的元素,直到它结束,然后继续到下一个,轻松处理有限和无限迭代器,同时保持确切的顺序。它对于合并数据源、创建复杂模式或优先处理迭代序列非常有用。

控制无限迭代

虽然无限迭代器会无限运行,但像 itertools.islice 这样的工具可以精确控制其输出。

controlled_iteration.py
from itertools import count, islice

# Infinite counter
nums = count(0)

# Take first 5 multiples of 3
threes = (x for x in nums if x % 3 == 0)
first_five_threes = islice(threes, 5)
print(list(first_five_threes))  # [0, 3, 6, 9, 12]

本示例演示了使用 islice 进行控制,它提取指定数量的项,并与 takewhile 进行对比,后者收集项直到条件失败。其他方法包括条件生成器表达式、带中断的手动 next 调用、时间限制或基于信号的终止。

内存效率考虑

无限迭代器通过按需生成值而不是预先存储整个序列来提高内存效率。

memory_efficiency.py
import sys
from itertools import count

# Infinite iterator
infinite = count()

# Regular list would fail
try:
    infinite_list = list(range(sys.maxsize + 1))
except MemoryError:
    print("Cannot create infinite list!")

# Iterator works fine
print(next(infinite))  # 0
print(next(infinite))  # 1

这些迭代器一次生成一个值,避免预先计算完整序列,处理超出内存限制的数据,并支持惰性求值。它们非常适合大型数据集、流式处理管道、受限环境或长时间运行的操作。

最佳实践

资料来源

作者

我叫 Jan Bodnar,是一名充满激情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 Python 教程