如何在 Python 中使用 yield 语句创建生成器函数

PythonPythonBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

yield 语句驱动的 Python 生成器函数提供了一种独特且高效的数据处理方式。在本教程中,我们将探讨生成器函数的基础知识,了解它们带来的好处,并指导你完成在 Python 中创建自己的生成器函数的过程。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/AdvancedTopicsGroup(["Advanced Topics"]) python/AdvancedTopicsGroup -.-> python/iterators("Iterators") python/AdvancedTopicsGroup -.-> python/generators("Generators") python/AdvancedTopicsGroup -.-> python/context_managers("Context Managers") subgraph Lab Skills python/iterators -.-> lab-397976{{"如何在 Python 中使用 yield 语句创建生成器函数"}} python/generators -.-> lab-397976{{"如何在 Python 中使用 yield 语句创建生成器函数"}} python/context_managers -.-> lab-397976{{"如何在 Python 中使用 yield 语句创建生成器函数"}} end

理解 Python 生成器

Python 生成器是一种特殊类型的函数,它允许你创建迭代器。与使用 return 语句返回一个值然后终止的常规函数不同,生成器使用 yield 语句返回一个值,然后暂停函数的执行,以便稍后可以恢复。

当你需要处理大型或无限数据集时,生成器特别有用,因为它们可以即时生成值,而不是将整个数据集存储在内存中。这使得它们比传统列表或其他数据结构更节省内存。

以下是 Python 中一个生成器函数的简单示例:

def count_up_to(n):
    i = 0
    while i < n:
        yield i
        i += 1

在这个示例中,count_up_to() 函数是一个生成器,它生成从 0 到(但不包括)n 值的数字。当你调用这个函数时,它会返回一个生成器对象,然后你可以迭代该对象以一次获取一个值。

>>> counter = count_up_to(5)
>>> for num in counter:
...     print(num)
0
1
2
3
4

如你所见,生成器函数在每个 yield 语句之后暂停其执行,允许 for 循环一次使用一个值。这与常规函数形成对比,常规函数会生成整个数字列表并一次性返回。

生成器可以是你 Python 编程工具库中的一个强大工具,理解它们的工作原理是成为一名熟练的 Python 开发者的重要组成部分。

介绍 yield 语句

yield 语句是 Python 中区分生成器函数与常规函数的关键特性。当你调用一个常规函数时,它会执行整个函数体,并使用 return 语句返回一个值。相比之下,使用 yield 语句的生成器函数可以暂停其执行,返回一个值,然后从停止的地方恢复执行。

以下是 yield 语句的工作方式:

  1. 当你调用一个生成器函数时,它返回一个生成器对象,而不是最终结果。
  2. 当你迭代生成器对象(例如,使用 for 循环)时,生成器函数会执行,直到到达 yield 语句。
  3. yield 语句返回指定的值,函数的执行暂停。
  4. 下次迭代生成器时,函数从停止的地方恢复执行,继续执行直到到达下一个 yield 语句。

这个过程会持续进行,直到生成器函数完成,此时它会引发一个 StopIteration 异常。

下面是一个说明 yield 语句用法的示例:

def count_up_to(n):
    i = 0
    while i < n:
        yield i
        i += 1

counter = count_up_to(5)
print(next(counter))  ## 输出:0
print(next(counter))  ## 输出:1
print(next(counter))  ## 输出:2
print(next(counter))  ## 输出:3
print(next(counter))  ## 输出:4
print(next(counter))  ## 引发 StopIteration

在这个示例中,count_up_to() 函数是一个生成器,它生成从 0 到(但不包括)n 值的数字。当我们对生成器对象调用 next() 时,它会返回序列中的下一个值,并且函数的执行会暂停,直到下一次调用 next()

yield 语句是在 Python 中创建生成器函数的关键,理解它的工作方式对于在代码中有效使用生成器至关重要。

生成器函数的优点

与传统函数和数据结构相比,Python 中的生成器函数具有以下几个优点:

内存效率高

生成器函数的主要优点之一是其内存效率。与一次性生成并返回整个结果集的常规函数不同,生成器函数一次只生成一个值,这意味着它们只在内存中存储当前值。当处理大型或无限数据集时,这使得它们特别有用,因为它们可以即时生成值而不会占用大量内存。

延迟求值

生成器函数采用延迟求值,这意味着它们只在需要时生成值,而不是预先生成整个序列。这在性能上可能具有显著优势,尤其是在处理计算成本高昂的操作或大型数据集时。

无限序列

生成器函数可用于创建无限序列,这对于列表或数组等传统数据结构来说是不可能的。这使得它们在生成没有预定长度的序列时非常有用,例如随机数、斐波那契数,甚至用户输入。

可组合性

生成器函数可以很容易地组合在一起,使你能够创建复杂的数据处理管道。这可以通过将生成器函数用作其他生成器函数的输入来实现,从而创建一系列可以高效执行的转换。

以下是一个展示生成器函数优点的示例:

import time

def fibonacci_generator(n):
    a, b = 0, 1
    for i in range(n):
        yield a
        a, b = b, a + b

## 内存高效的斐波那契数列
fibonacci = fibonacci_generator(1000000)
for num in fibonacci:
    pass  ## 对斐波那契数进行某些操作

## 延迟求值
def square_numbers(nums):
    for num in nums:
        time.sleep(0.1)  ## 模拟计算成本高昂的操作
        yield num ** 2

squares = square_numbers(range(10))
for square in squares:
    print(square)

在这个示例中,fibonacci_generator() 函数通过生成高达 100 万的斐波那契数列而不占用大量内存,展示了生成器函数的内存效率。square_numbers() 函数展示了生成器的延迟求值特性,即只有在需要时才计算平方值。

通过理解生成器函数的优点,你可以编写更高效、更强大的 Python 代码,轻松处理大型或无限数据集。

总结

在本教程结束时,你将对 Python 生成器函数和 yield 语句有扎实的理解。你将能够创建自己的生成器函数,利用它们在内存优化和高效数据处理方面的优势。掌握这一 Python 编程技术将为你提供一个强大的工具,以提高应用程序的性能和可扩展性。