Python 中的迭代器与可迭代对象:高效执行迭代

更新于 2026-01-12

Leodanis Pozo Ramos

当你编写计算机程序时,经常需要多次重复执行某段代码。为此,你可以采用以下方法之一:

  • 顺序重复目标代码所需次数
  • 将目标代码放入一个循环中,按需运行多次

第一种方法存在一些缺点,最麻烦的问题是重复代码本身难以维护且不可扩展。例如,以下代码会在屏幕上打印三次问候语:

# greeting.py
print("Hello!")
print("Hello!")
print("Hello!")

运行此脚本后,你会看到 'Hello!' 被打印三次。这段代码虽然有效,但如果你决定将消息更新为 'Hello, World!',就必须修改三行代码,这带来了维护负担。

想象一下,如果面对的是更大、更复杂的代码块,维护工作可能会变成一场噩梦。

使用循环是解决该问题并避免可维护性问题的更好方式。循环允许你按需多次运行一段代码。例如,使用 while 循环重写上述示例:

>>> times = 0
>>> while times < 3:
...     print("Hello!")
...     times += 1
...
Hello!
Hello!
Hello!

这个 while 循环会持续运行,只要循环继续条件(times < 3)为真。每次迭代中,循环都会打印问候消息并递增控制变量 times。现在,如果你要更新消息,只需修改一行代码,大大提升了可维护性。

Python 的 while 循环支持所谓的不定次迭代(indefinite iteration),即反复执行同一代码块,可能执行次数不确定。

你还可能遇到另一种类似但不同的迭代类型——定次迭代(definite iteration),即按预定义次数遍历相同代码。当你需要逐个遍历数据流中的项目时,这种迭代特别有用。

在 Python 中,通常使用 for 循环来实现此类迭代:

>>> numbers = [1, 2, 3, 4, 5]
>>> for number in numbers:
...     print(number)
...
1
2
3
4
5

在此示例中,numbers 列表代表你的数据流,你通常将其泛称为可迭代对象(iterable),因为你可以在其上进行迭代(稍后会详细介绍)。

当你使用 whilefor 循环多次重复执行代码时,实际上就是在运行迭代(iteration)。这是对该过程本身的命名。


认识 Python 迭代器

迭代器通过 PEP 234 在 Python 2.2 中引入。它们是对语言的重要补充,因为它们统一了迭代过程,并将其从容器数据类型的实现细节中抽象出来。这种抽象使得即使对无序集合(如集合 set)也能确保每个元素恰好被访问一次。

什么是 Python 迭代器?

在 Python 中,迭代器是一个允许你遍历数据集合(如列表、元组、字典和集合)的对象。

Python 迭代器实现了迭代器设计模式,允许你遍历容器并访问其元素。该模式将迭代算法与容器数据结构解耦。

迭代器主要负责两项操作:

  • 一次返回数据流或容器中的一个项目
  • 跟踪当前项和已访问项

简而言之,迭代器会在维护迭代状态所需的所有内部记录的同时,从集合或数据流中逐个生成每个项目或值。

Python 迭代器必须实现一个广为人知的内部结构——迭代器协议

什么是 Python 迭代器协议?

当一个 Python 对象实现了两个特殊方法(合称迭代器协议)时,它就被视为迭代器。这两个方法使 Python 迭代器得以工作。因此,如果你想创建自定义迭代器类,就必须实现以下方法:

方法 描述
.__iter__() 用于初始化迭代器,必须返回一个迭代器对象。
.__next__() 用于迭代,必须返回数据流中的下一个值。

迭代器的 .__iter__() 方法通常返回 self(即当前对象:迭代器本身)。该方法的实现通常如下:

def __iter__(self):
    return self

.__iter__() 的唯一职责是返回一个迭代器对象,因此通常直接返回 self(前提是该实例定义了 .__next__() 方法)。

.__next__() 方法则根据需求更复杂一些。它必须返回数据流中的下一个项目,并在数据流中没有更多项目时抛出 StopIteration 异常。该异常将终止迭代过程。没错,迭代器使用异常进行流程控制

何时在 Python 中使用迭代器?

Python 迭代器最常见的用例是允许遍历数据流或容器数据结构。Python 在底层使用迭代器来支持所有需要迭代的操作,包括 for 循环、推导式、可迭代解包等。因此,你其实一直在无意识地使用迭代器。

在日常编程中,当你需要遍历未知数量或海量数据集时,迭代器非常有用。这些数据可能来自本地磁盘、数据库或网络。

在这些情况下,迭代器允许你一次只处理一个项目,而不会耗尽系统内存资源——这是迭代器最吸引人的特性之一。


创建不同类型的迭代器

通过在类中使用构成迭代器协议的两个方法,你可以编写至少三种不同类型的自定义迭代器:

  1. 接收数据流,并按原样逐个生成数据项
  2. 接收数据流,转换每个项目,然后生成转换后的项目
  3. 不接收输入数据,而是通过某种计算生成新数据,最终生成这些数据项

第一种迭代器是你所说的经典迭代器,因为它实现了原始的迭代器模式。第二和第三种则通过新增功能进一步拓展了该模式的能力。

注意:第二和第三种迭代器可能让你联想到函数式编程中的映射(mapping)和过滤(filtering)操作。

生成原始数据

作为第一个示例,你将编写一个名为 SequenceIterator 的经典迭代器。它接收一个序列类型作为参数,并按需生成其项目。

# sequence_iter.py
class SequenceIterator:
    def __init__(self, sequence):
        self._sequence = sequence
        self._index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self._index < len(self._sequence):
            item = self._sequence[self._index]
            self._index += 1
            return item
        else:
            raise StopIteration

SequenceIterator 在实例化时接收一个值序列。.__init__() 方法负责创建适当的实例属性,包括输入序列和 _index 属性(用于通过索引遍历序列)。

.__iter__() 方法仅返回当前对象 self(即迭代器本身,它必须有 .__next__() 方法)。

.__next__() 方法中,先检查当前索引是否小于输入序列的项目数。如果是,则获取当前项,递增 _index,并返回该项;否则抛出 StopIteration 异常以结束迭代。

使用示例:

>>> from sequence_iter import SequenceIterator
>>> for item in SequenceIterator([1, 2, 3, 4]):
...     print(item)
...
1
2
3
4

注意:你可以创建一个不定义 .__iter__() 方法的迭代器,此时 .__next__() 仍可工作。但若想在 for 循环中使用,必须实现 .__iter__(),因为循环总会调用它来初始化迭代器。

转换输入数据

假设你想编写一个迭代器,接收数字序列,计算每个数字的平方值,并按需生成这些平方值:

# square_iter.py
class SquareIterator:
    def __init__(self, sequence):
        self._sequence = sequence
        self._index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self._index < len(self._sequence):
            square = self._sequence[self._index] ** 2
            self._index += 1
            return square
        else:
            raise StopIteration

使用示例:

>>> from square_iter import SquareIterator
>>> for square in SquareIterator([1, 2, 3, 4, 5]):
...     print(square)
...
1
4
9
16
25

这种数据转换功能非常高效:它不会一次性将所有结果存入内存(如创建新列表),而是按需计算,节省大量内存。

生成新数据

你还可以创建不依赖输入数据流、而是通过计算生成新数据的迭代器。例如,生成斐波那契数列:

# fib_iter.py
class FibonacciIterator:
    def __init__(self, stop=10):
        self._stop = stop
        self._index = 0
        self._current = 0
        self._next = 1

    def __iter__(self):
        return self

    def __next__(self):
        if self._index < self._stop:
            self._index += 1
            fib_number = self._current
            self._current, self._next = self._next, self._current + self._next
            return fib_number
        else:
            raise StopIteration

使用示例(默认生成10个斐波那契数):

>>> from fib_iter import FibonacciIterator
>>> for fib_number in FibonacciIterator():
...     print(fib_number)
...
0
1
1
2
3
5
8
13
21
34

编写潜在无限迭代器

Python 迭代器可以处理潜在无限的数据流。只需省略 StopIteration 即可:

# inf_fib.py
class FibonacciInfIterator:
    def __init__(self):
        self._current = 0
        self._next = 1

    def __iter__(self):
        return self

    def __next__(self):
        self._current, self._next = self._next, self._current + self._next
        return self._current

警告:无限循环会导致程序挂起!在 REPL 中可按 Ctrl+C 终止。


collections.abc.Iterator 继承

collections.abc 模块包含一个名为 Iterator 的抽象基类(ABC)。继承它可快速创建自定义迭代器:

from collections.abc import Iterator

class SequenceIterator(Iterator):
    def __init__(self, sequence):
        self._sequence = sequence
        self._index = 0

    def __next__(self):
        if self._index < len(self._sequence):
            item = self._sequence[self._index]
            self._index += 1
            return item
        else:
            raise StopIteration

这样就不必手动实现 .__iter__() 方法了。


创建生成器迭代器

生成器函数是一种特殊函数,允许你以函数式风格创建迭代器。与普通函数不同,生成器函数使用 yield 语句返回一个生成器迭代器,可逐个生成数据流。

注意:Python 中“生成器”一词通常指两个概念:

  • 生成器函数:使用 yield 定义的函数
  • 生成器迭代器:该函数返回的对象

创建生成器函数

>>> def sequence_generator(sequence):
...     for item in sequence:
...         yield item
...
>>> for number in sequence_generator([1, 2, 3, 4]):
...     print(number)
...
1
2
3
4

生成器函数比基于类的迭代器更简洁易懂。

使用生成器表达式

生成器表达式的语法与列表推导式几乎相同,只需将方括号 [] 改为圆括号 ()

>>> (item for item in [1, 2, 3, 4])
<generator object <genexpr> at 0x...>
>>> gen = (item for item in [1, 2, 3, 4])
>>> for item in gen:
...     print(item)
...
1
2
3
4

不同类型的生成器迭代器

生成器也可用于:

  • 按原样生成输入数据
  • 转换输入并生成新数据流
  • 通过计算生成全新数据流(无需输入)

示例1:平方生成器

>>> def square_generator(sequence):
...     for item in sequence:
...         yield item ** 2
...
>>> list(square_generator([1, 2, 3, 4, 5]))
[1, 4, 9, 16, 25]

示例2:斐波那契生成器

>>> def fibonacci_generator(stop=10):
...     current, next_val = 0, 1
...     for _ in range(stop):
...         yield current
...         current, next_val = next_val, current + next_val
...
>>> list(fibonacci_generator(5))
[0, 1, 1, 2, 3]

使用迭代器进行内存高效的数据处理

迭代器和生成器比普通函数、容器类型和推导式更节省内存,因为它们不会同时将所有数据存储在内存中,而是按需生成。

返回迭代器而非容器类型

普通函数通常创建列表等容器存储结果:

>>> def square_list(numbers):
...     return [n**2 for n in numbers]
...
>>> square_list([1,2,3,4])
[1, 4, 9, 16]

而生成器只在需要时计算单个值,大幅降低内存占用。

构建数据处理管道

可将多个生成器函数组合成内存高效的数据处理管道

# math_pipeline.py
def to_square(numbers): return (n**2 for n in numbers)
def to_even(numbers):   return (n for n in numbers if n % 2 == 0)
def to_string(numbers): return (str(n) for n in numbers)

# 使用管道
>>> import math_pipeline as mpl
>>> list(mpl.to_string(mpl.to_square(mpl.to_even(range(10)))))
['0', '4', '16', '36', '64']

Python 迭代器的一些限制

尽管迭代器功能强大,但也存在一些约束:

  1. 不可重复迭代:迭代器一旦耗尽,无法再次使用
  2. 无法重置:耗尽后必须创建新迭代器
  3. 只能前进:不支持反向遍历(无 .__previous__()
  4. 无法获取长度:不知道总共有多少项
  5. 不支持索引/切片:不能使用 obj[2]obj[1:3]

解决方案:可创建支持多次迭代的类(如 ReusableRange)。


使用内置 next() 函数

next() 函数用于从迭代器获取下一项(内部调用 .__next__()):

>>> numbers = iter([1, 2, 3])
>>> next(numbers)
1
>>> next(numbers, 0)  # 提供默认值
2
>>> next(numbers, 0)
3
>>> next(numbers, 0)  # 耗尽后返回默认值
0

常见用途:跳过 CSV 文件的标题行

with open("data.csv") as f:
    next(f)  # 跳过首行
    for line in f:
        process(line)

认识 Python 可迭代对象(Iterables)

可迭代对象是可以被迭代的对象(如列表、元组、字符串等)。关键区别:

特性 迭代器 可迭代对象
可直接用于 for 循环
可多次迭代
支持 next()
保存迭代状态
内存高效

可迭代协议

对象只要实现 .__iter__() 方法(返回迭代器)或 .__getitem__() 方法(支持索引),就是可迭代的。

示例:使栈可迭代

class Stack:
    def __init__(self):
        self._items = []
    
    def push(self, item):
        self._items.append(item)
    
    def __iter__(self):
        return iter(self._items)  # 或使用 yield / yield from

异步迭代器(Async Iterators)

Python 3.7+ 支持异步迭代,使用 async for 循环:

# async_rand.py
import asyncio
from random import randint

class AsyncIterable:
    def __init__(self, stop):
        self._stop = stop
        self._index = 0
    
    def __aiter__(self):
        return self
    
    async def __anext__(self):
        if self._index >= self._stop:
            raise StopAsyncIteration
        await asyncio.sleep(value := randint(1, 3))
        self._index += 1
        return value

# 使用
>>> async def main():
...     async for n in AsyncIterable(3):
...         print(n)
...
>>> asyncio.run(main())
2
1
3

异步迭代器协议:

  • .__aiter__() → 返回自身
  • .__anext__() → 返回可等待对象,耗尽时抛出 StopAsyncIteration

总结

通过本教程,你已掌握:

  • 如何使用迭代器协议创建自定义迭代器
  • 迭代器与可迭代对象的区别及使用场景
  • 如何用生成器函数和表达式创建生成器迭代器
  • 如何构建内存高效的数据处理管道
  • 如何编写异步迭代器

现在,你已能根据需求选择合适的工具,在代码中充分发挥迭代器与可迭代对象的强大能力!