欢迎访问宙启技术站
智能推送

Python函数-如何使用生成器函数和yield关键字?

发布时间:2023-06-15 09:44:43

Python的生成器函数和yield关键字可以帮助开发人员解决内存问题,尤其是在处理大量数据时。生成器函数可以按需生成值,并且只在需要时才占用内存。

在本文中,我们将探讨如何编写和使用生成器函数和yield关键字,并使用实例说明。

1. 生成器函数是什么?

生成器函数是一种特殊的Python函数,它使用yield关键字返回值。yield关键字会暂停函数的执行,并在下一次调用时从停止的位置恢复执行。

当我们在一个函数中使用yield时,我们并不是要返回一个值,而是暂停该函数在当前的位置。下一次函数被调用时,它从上一次停止的地方继续执行。

2. 生成器函数和常规函数的不同之处

生成器函数与普通函数的最大区别是,生成器函数可以生成一系列值。相比之下,普通函数只能生成一个值并且仍在内存中。

例如,我们可以编写一个通常的函数来计算要打印的所有奇数的总和:

def sum_of_odd_numbers(n):
    total = 0
    for i in range(1, n+1):
        if i % 2 != 0:
            total += i
    return total

当我们对它进行测试时,我们可以发现这个函数返回给我们一个整数:

sum_of_odd_numbers(10)
25

相反,如果我们使用生成器函数返回所有奇数,那么我们可以编写如下的代码:

def odd_numbers(n):
    for i in range(1, n+1):
        if i % 2 != 0:
            yield i

我们将函数odd_numbers作为一个生成器使用。我们可以从该生成器中获得一些值:

>>> for x in odd_numbers(10):
...     print(x)
... 
1
3
5
7
9

正如我们所见,函数odd_numbers返回了一个生成器。每当我们使用它时,它就会在下一个奇数处暂停,提供下一项值。

这可以概括为“每次当我们使用生成器函数时,它都会返回一个可迭代对象,我们可以使用这个对象来获得一些计算结果。”

3. 生成器表达式

与列表推导式类似,我们也可以使用生成器表达式。生成器表达式是一种简洁的语法,可以轻松创建一个生成器。

例如,下面的生成器表达式将创建一个生成器,用于在给定列表中找到所有元素的平方,并返回这些平方:

>>> squares = (x**2 for x in [1, 2, 3, 4, 5])
>>> squares
<generator object <genexpr> at 0x7f89340e0fc0>
>>> list(squares)
[1, 4, 9, 16, 25]

当您使用生成器表达式时,它可以返回一些值,并不像列表推导式必须返回一个列表。这意味着它可以返回一个更少的内存占用。

4. 组合生成器

在Python中,您可以轻松组合生成器。假设您要在生成器中创建一个新的生成器。

例如,我们可以编写一个生成器,该生成器将大于5的偶数平方,并创建一个组合生成器,该生成器将其摇篮扩大2倍,并返回其值。

def even_squares(n):
    for i in range(1, n+1):
        if i % 2 == 0 and i > 5:
            yield i**2

def doubled(iterable):
    for i in iterable:
        yield i*2

组合生成器将使用先前的两个生成器odd_numbers和doubled组合在一起,生成大于5的偶数的2倍平方数。

>>> even_squares_generator = even_squares(20)
>>> result = doubled(even_squares_generator)
>>> list(result)
[216, 256, 324, 400]

如您所见,生成器可以很容易地组合在一起,我们可以在过程中让它占用最少的内存。

5. 递归生成器

递归是一种有趣的编程技术。当您编写递归函数时,函数将调用自身,直到达到基本情况。

在Python中,您也可以使用递归生成器。例如,下面是一个递归生成器,该生成器将生成Fibonacci数列:

def fibonacci():
    a, b = 0, 1
      while True:
        yield a
        a, b = b, a + b

当我们使用这个生成器时,它一直会生成下一个Fibonacci值。

>>> generator = fibonacci()
>>> [next(generator) for _ in range(20)]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]

6. with语句和生成器

with语句用于处理上下文资源,并在不再需要它们时自动释放它们。您可以使用生成器来定义您自己的with块。

下面是一个使用生成器函数的with块的示例。这个with块用于处理文件的自动关闭:

from contextlib import contextmanager

@contextmanager
def open_file(name):
    f = open(name, 'w')
    try:
        yield f
    finally:
        f.close()

在这个函数中,我们打开一个文件,并使用try-finally语句来确保文件在使用后被正确关闭。

我们使用生成器装饰器 @contextmanager 来将这个函数转换为上下文管理器。当您使用with块访问该函数时,它将确保在使用文件后自动关闭文件。

>>> with open_file('test.txt') as f:
...     f.write('hello python')

7. 结论

在本文中,我们学习了如何使用Python的生成器函数和yield关键字。我们了解了生成器函数和普通函数的不同之处,如何使用生成器表达式、组合生成器、递归生成器和with语句,以及如何避免内存问题。

在我们的实际开发中,使用生成器函数和yield关键字可能会带来许多好处。生成器可以帮助我们解决内存问题并提高代码质量。希望这篇文章对大家有所帮助,谢谢!