龙空技术网

如何在 Python 中使用“yield”?

树哥会编程 1090

前言:

现时你们对“pythonyield”可能比较着重,朋友们都需要剖析一些“pythonyield”的相关内容。那么小编同时在网摘上网罗了一些有关“pythonyield””的相关内容,希望姐妹们能喜欢,各位老铁们快快来学习一下吧!

如果你是 Python 开发者,相信你一定知道 Python 中的 生成器。定义 Python 生成器的关键是使用“yield”关键字。Python 生成器普遍用于需要大集合的场景,提高代码的可读性以及多线程等其他特定场景。

你可能知道也可能不知道如何正确使用“yield”关键字。在本文中,我将从基本用法介绍 Python 生成器。后面的部分还将介绍一些更高级的使用模式。

1. 基础

让我们在本教程中编写一个示例。假设我们公司有一群人需要一个一个待命。所以,这将是一个轮换名单。

names = ["alice","bob","chris","jack","elio"]

现在,我们要从这个名称列表中定义一个 Python 生成器。代码如下。

def gen_roster(names):    for name in names:        yield name

请注意,我们需要使用yield关键字而不是return,因此我们可以使用此函数来制作生成器。

names = ["alice","bob","chris","jack","elio"]def gen_roster(names):    for name in names:        yield nameroster = gen_roster(names)print(type(roster))

运行输出:

现在,我们得到了rosterPython 生成器也是可迭代的,因此我们可以将其放入 for 循环中,一次性获取所有name

names = ["alice","bob","chris","jack","elio"]def gen_roster(names):    for name in names:        yield nameroster = gen_roster(names)for name in roster:    print(name)

运行输出:

2. 使用__next__方法

好吧,在前面的示例中,在 for 循环中使用生成器并没有太大意义。使用生成器的好处是我们可以一次获得一个值。当我们处理大量集合时,这可能非常有用。也就是说,当我们创建一个生成器时,项目不会被读入内存。只有当我们试图获取下一个项目并点击yield关键字时,才会生成该项目。

因此,无论如何,重要的是获得生成器的“下一个”元素。在这种情况下,我们可以使用它的__next__()方法。

roster.__next__()

其实我们也可以按照下面的方式来做,更直观,更容易记忆。

next(roster)

你是否注意到当我们试图获取“下一个”列表元素“光标”被移动了?还记得我们在生成器的定义中定义了一个 for 循环吗?我们可以认为 for 循环将每次执行一次,直到到达关键字为止yield

这也意味着,我们的“光标”目前位于第三个名称。因此,如果我们尝试输出所有其余的项目,“alice”和“bob”将被跳过。

现在,“光标”在末尾。如果我们尝试获取下一个项目,则会抛出错误,因为没有更多列表元素。

这实际上不是我们想要的,因为name将用于决定谁在当前轮换中待命。换句话说,我们希望“光标”回到开头,这样所有的名字都会再次循环。

诀窍是简单的while True在 for 循环之上放置一个语句。因此,一旦所有名称都用完,for 循环将重新开始。

def gen_roster(names):     while True:         for name in names:             yield name

现在,假设我们想要一个有 12 个名字的名单。我们只有 5 名员工。因此,它们将被旋转。

names = ["alice","bob","chris","jack","elio"]def gen_roster(names):     while True:         for name in names:             yield nameroster = gen_roster(names)for i in range(12):    print(next(roster))

如果我们不输入数字“12”,则生成器可以无限期地生成更多name。

向生成器发生一个值

生成器的一种高级用法是向生成器发送一个值。该值将成为当前yield 表达式的结果,该方法返回生成器生成的下一个值。

所以,不要指望生成器会返回我们刚刚发送的值,因为它会返回下一个。但是,我们可以使用它在生成器内部做一些事情。例如,我们可以通过向无限生成器发送某个值来停止它。

def gen_roster(names):     while names:         for name in names:             current_name = yield name             if current_name == 'stop':                 names = None                 break

如果从外部发送值“stop”,则生成器已定义为终止循环。因此,我们可以验证如下行为。

names = ["alice","bob","chris","jack","elio"]def gen_roster(names):     while names:         for name in names:             current_name = yield name             if current_name == 'stop':                 names = None                 break                roster = gen_roster(names)for i in range(10):    if i == 3:        roster.send('stop')    print(next(roster))

运行输出:

在上面的代码中,我们要求程序循环 10 次。然而,对于第 4 轮,我们将值“stop”传递给生成器。结果,只输出了 3 个名字,并且生成器在第 4 轮就停止了,而不是循环了 10 次。

当我们想要在多线程编程场景中更改生成器的行为或规则时,send 方法将非常有用。

停止生成器—抛出异常并关闭

当出现异常问题时,我们可以使用该throw()方法在生成器暂停时引发异常。我们可以自定义错误类型。出于本文章中的演示目的,为了方便起见,我将简单地使用“TypeError”。

names = ["alice","bob","chris","jack","elio"]def gen_roster(names):     while names:         for name in names:             current_name = yield name             if current_name == 'stop':                 names = None                 breakroster = gen_roster(names)next_name = roster.throw(TypeError, 'Stop!')

如果没有出错,但我们仍然想终止生成器,我们可以使用close()生成器的方法。当我们有一个无限生成器并且我们想在某个点停止它时,这将非常有用

names = ["alice","bob","chris","jack","elio"]def gen_roster(names):     while names:         for name in names:             current_name = yield name             if current_name == 'stop':                 names = None                 breakroster = gen_roster(names)for i in range(10):    if i == 3:        roster.close()    print(next(roster))

运行输出:

上面的代码在第 4 轮关闭了生成器“roster”,所以当下一个循环试图获取下一个值时,就会抛出异常

总结

在本文中,我介绍了 Python 中最重要的“Pythonic”概念之一生成器。关键字的使用yield是 Python 生成器的关键。

不仅介绍了基本用法,还介绍了一些高级用法,例如从外部向生成器发送值、引发异常和关闭生成器。希望它可以帮助你更多地了解 Python 生成器。

如果你发现我的任何文章对你有帮助或有用,麻烦点赞或者转发。 谢谢!

标签: #pythonyield #pythonyield函数 #python中yield函数怎么用 #python yieid #python中yield函数的用法