【Python 进阶】yield 关键词

【Python 进阶】yield 关键词

Fre5h1nd Lv5

💡简介

  • 写小脚本中的读取文件模块时,copilot 推荐了一段带有 yield 的代码,突然意识到对 Python 的一些进阶用法很不熟悉,正好基于相关资料
    [1][2]进行总结。

🖼️背景

  • 当我们需要用到一组数据时,一种简单的方案是把它们全部提前生成/读入,保存在列表变量,存储在内存中。
  • 这种方案的一个明显缺点是:内存占用过大。
    • 在日常使用中可能不会造成什么明显后果,但当涉及的数据过多时就会对性能产生很大影响。
    • 尤其是面对未知大小的文件,直接读入会导致不可预测的内存占用。

案例——生成斐波那契数列

1
2
3
4
5
6
7
8
9
10
11
12
# 简单方案
def fibonacci(max):
n, a, b = 0, 0, 1
L = []
while n < max:
L.append(b)
a, b = b, a + b
n = n + 1
return L

for x in fibonacci(1000):
print(x)

🧠解决思路:延迟生成

  • 数据之间可能存在一些逻辑关系,例如:
    • 斐波那契数列中,前两个数产生第三个数
    • 文件读取时,前一行数据的下一个位置是后一行数据的开头
  • 我们可以用记录数据之间的逻辑关系来代替记录具体数据,更进一步地,仅当需要时才通过之前的数据逻辑关系获得所需数据,也就是将数据的生成/读入过程延迟到数据被需要的时候

🔨解决方案 1️⃣:迭代器

  • 将上文中 fibonacci 函数改造为一个使用迭代器的类,迭代器不断生成下一个数。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 迭代器方案
    class Fibonacci:

    def __init__(self, max):
    self.max = max
    self.n, self.a, self.b = 0, 0, 1

    def __iter__(self):
    return self

    def __next__(self):
    if self.n < self.max:
    r = self.b
    self.a, self.b = self.b, self.a + self.b
    self.n = self.n + 1
    return r
    raise StopIteration()

    for x in Fibonacci(1000):
    print(x)
  • 很显然,这种方案带来的一个问题是复杂的代码格式,需要多写很多配置,不够优雅。

🔨解决方案 2️⃣:yield

  • 使用 yield 关键字,可以很优雅地使函数成为一个生成器 generator。
  • 看起来 fibonacci 函数仍然是个普通函数,但其返回值实际上是一个迭代器。(非常优雅)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # yield方案
    def fibonacci(max):
    n, a, b = 0, 0, 1
    while n < max:
    yield b
    a, b = b, a + b
    n = n + 1

    for x in fibonacci(1000):
    print(x)

    f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
    while True:
    try:
    print(next(f), end=" ")
    except StopIteration:
    sys.exit()

💡原理

  • 根据直观理解,yield 关键词和 return 关键词类似,能够返回一个东西。猜测可能是解释器看到 yield 时返回一个迭代器,并将相关代码赋给该迭代器。
  • 感兴趣的小伙伴可以根据相关资料[3]理解一下底层原理。


  • 希望这篇博客对你有帮助!如果你有任何问题或需要进一步的帮助,请随时提问。
  • 如果你喜欢这篇文章,欢迎动动小手 给我一个follow或star。

🗺参考文献

[1] Python3 迭代器与生成器

[2] Python yield 使用浅析

[3] 深度详解 Python yield与实现

  • 标题: 【Python 进阶】yield 关键词
  • 作者: Fre5h1nd
  • 创建于 : 2023-09-13 14:10:13
  • 更新于 : 2023-12-08 20:31:54
  • 链接: https://freshwlnd.github.io/2023/09/13/program_language/python/py-yield/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论