当前位置:首页>python>【一起学Python】第18天:迭代器与生成器

【一起学Python】第18天:迭代器与生成器

  • 2026-08-26 10:46:36
【一起学Python】第18天:迭代器与生成器
在 Python 中,迭代是其最强大的功能之一,它允许我们以一种统一的方式访问集合中的每一个元素。本文将深入探讨 Python 中的两种核心迭代机制:迭代器(Iterator) 和 生成器(Generator)。我们将详细介绍它们的概念、工作原理、如何创建和使用它们,并通过丰富的代码示例来加深理解。
一、迭代器(Iterator)
迭代器是一个可以记住遍历位置的对象。它从集合的第一个元素开始访问,直到所有元素被访问完毕。迭代器的一个关键特性是它只能向前移动,不能后退。
1.1 迭代器的基本方法:iter() 和 next()
Python 中,任何可迭代对象(如列表、元组、字符串)都可以通过 iter() 函数来创建一个迭代器。然后,我们可以使用 next() 函数来逐个访问迭代器中的元素。
# 创建一个列表my_list = [1, 2, 3, 4]# 从列表创建一个迭代器my_iterator = iter(my_list)# 使用 next() 访问元素print(next(my_iterator))  # 输出: 1print(next(my_iterator))  # 输出: 2
当迭代器中没有更多元素时,再次调用 next() 会引发一个 StopIteration 异常。
1.2 使用 for 循环遍历迭代器
for 循环在后台自动处理了 iter() 和 next() 的调用以及 StopIteration 异常。这是遍历迭代器最常见和推荐的方式。
my_list = [1, 2, 3, 4]my_iterator = iter(my_list)for item in my_iterator:    print(item, end=" ")  # 输出: 1 2 3 4
1.3 创建自定义迭代器

要创建一个自定义的迭代器,我们需要在一个类中实现两个特殊方法:__iter__() 和 __next__()。

  • __iter__(): 这个方法返回迭代器对象本身。它在 for 循环开始时被调用一次。

  • __next__(): 这个方法返回序列中的下一个项目。在 for 循环的每次迭代中,它都会被调用。

示例:创建一个生成从1开始的数字的迭代器

class MyNumbers:    def __iter__(self):        self.a = 1        return self    def __next__(self):        x = self.a        self.a += 1        return xmy_class = MyNumbers()my_iter = iter(my_class)print(next(my_iter)) # 输出: 1print(next(my_iter)) # 输出: 2

1.4 使用 StopIteration 结束迭代

为了防止无限循环,__next__() 方法必须在迭代完成时引发 StopIteration 异常。我们可以通过添加一个条件来控制迭代的次数。
示例:创建一个迭代20次后停止的迭代器
class MyNumbers:    def __iter__(self):        self.a = 1        return self    def __next__(self):        if self.a <= 20:            x = self.a            self.a += 1            return x        else:            raise StopIterationmy_class = MyNumbers()my_iter = iter(my_class)for x in my_iter:    print(x)
二、生成器(Generator)

生成器是创建迭代器的更简单、更优雅的方式。在 Python 中,任何使用了 yield 关键字的函数都称为生成器函数。

yield 的工作方式类似于 return,但它会保存函数的状态。当再次调用生成器时,它会从上次离开的地方继续执行。

2.1 创建和使用生成器

调用一个生成器函数会返回一个迭代器对象,然后我们可以像使用普通迭代器一样使用它。

示例:一个简单的倒计时生成器

def countdown(n):    while n > 0:        yield n        n -= 1# 创建生成器对象generator = countdown(5)# 使用 next() 获取值print(next(generator))  # 输出: 5print(next(generator))  # 输出: 4# 使用 for 循环迭代for value in generator:    print(value) # 输出: 3 2 1

2.2 生成器的优势

生成器的主要优势在于内存效率。它们是“懒惰”的,按需生成值,而不是一次性在内存中创建整个序列。这使得它们在处理大数据集或无限序列时非常有用。

示例:使用生成器实现斐波那契数列

def fibonacci(n):    a, b, counter = 0, 1, 0    while counter < n:        yield a        a, b = b, a + b        counter += 1f = fibonacci(10)for num in f:    print(num, end=" ") # 输出: 0 1 1 2 3 5 8 13 21 34
三、逻辑流程
3.1 迭代器逻辑流程
  • 创建可迭代对象: 首先,有一个可迭代的数据集合,如列表、元组或字符串。

  • 获取迭代器: 使用 iter() 函数从可迭代对象中获取一个迭代器对象。

  • 循环/调用 next():

    1.for 循环: for 循环开始,它会自动调用迭代器的 __iter__() 方法(虽然对于迭代器本身来说,这只是返回 self)。

    2.在循环的每一次迭代中,for 循环内部会调用迭代器的 __next__() 方法来获取下一个元素。

    3.手动调用: 或者,你可以手动重复调用 next() 函数来获取元素。

    4.处理元素: 对从 __next__() 或 next() 获取的元素执行所需的操作。

  • 检测 StopIteration:

    1.for 循环: 当 __next__() 方法引发 StopIteration 异常时,for 循环会自动捕获这个异常并优雅地退出循环。

    2.手动调用: 如果是手动调用 next(),你需要使用 try...except StopIteration 块来捕获异常并处理迭代结束的情况。

  • 迭代结束: 循环或手动调用过程结束。

3.2 生成器逻辑流程

  • 定义生成器函数: 创建一个包含 yield 关键字的函数。

  • 创建生成器对象: 调用生成器函数。这不会立即执行函数体,而是返回一个生成器对象(它本身就是一个迭代器)。

  • 开始迭代:

    1.for 循环: 当 for 循环开始遍历生成器对象时,它会触发生成器函数的执行。

    2.手动调用 next(): 第一次调用 next() 也会触发生成器函数的执行。

  • 执行到 yield: 函数代码从头开始执行,直到遇到第一个 yield 语句。

  • 产出值并暂停: yield 语句会产出一个值(这个值成为 for 循环当前迭代的项或 next() 的返回值),然后函数的执行状态被冻结(所有局部变量和指令指针都被保存),并暂停。

  • 继续迭代:

    1.for 循环: 在下一次迭代中,for 循环会再次“唤醒”生成器函数。

    2.手动调用 next(): 下一次调用 next() 也会“唤醒”函数。

  • 从暂停处恢复: 函数从上次 yield 语句之后的地方继续执行,直到遇到下一个 yield 语句,然后重复第5步。

  • 函数结束或 return: 如果函数执行到末尾,或者遇到一个 return 语句(在Python 3.3+中,生成器中的 return 会引发 StopIteration),生成器会引发一个 StopIteration 异常。

  • 迭代结束: for 循环捕获 StopIteration 并退出。如果是手动调用,你需要自己处理这个异常。

结论

迭代器和生成器是 Python 中用于处理序列数据的强大工具。迭代器提供了一种通用的、内存高效的访问集合元素的方式,而生成器则提供了一种更简洁、更强大的语法来创建迭代器。理解并熟练运用它们,将极大地提升你的 Python 编程效率和代码质量。

最新文章

随机文章