百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

如何在 Python 中使用“yield”?_pythonyield详解

itomcoil 2025-02-17 12:30 11 浏览

如果你是 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 name
roster = gen_roster(names)
print(type(roster))

运行输出:

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

names = ["alice","bob","chris","jack","elio"]
def gen_roster(names):
    for name in names:
        yield name
roster = 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 name
roster = 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 
                break
roster = 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 
                break
roster = gen_roster(names)
for i in range(10):
    if i == 3:
        roster.close()
    print(next(roster))

运行输出:

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

总结

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

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

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

相关推荐

Excel新函数TEXTSPLIT太强大了,轻松搞定数据拆分!

我是【桃大喵学习记】,欢迎大家关注哟~,每天为你分享职场办公软件使用技巧干货!最近我把WPS软件升级到了版本号:12.1.0.15990的最新版本,最版本已经支持文本拆分函数TEXTSPLIT了,并...

Excel超强数据拆分函数TEXTSPLIT,从入门到精通!

我是【桃大喵学习记】,欢迎大家关注哟~,每天为你分享职场办公软件使用技巧干货!今天跟大家分享的是Excel超强数据拆分函数TEXTSPLIT,带你从入门到精通!TEXTSPLIT函数真是太强大了,轻松...

看完就会用的C++17特性总结(c++11常用新特性)

作者:taoklin,腾讯WXG后台开发一、简单特性1.namespace嵌套C++17使我们可以更加简洁使用命名空间:2.std::variant升级版的C语言Union在C++17之前,通...

plsql字符串分割浅谈(plsql字符集设置)

工作之中遇到的小问题,在此抛出问题,并给出解决方法。一方面是为了给自己留下深刻印象,另一方面给遇到相似问题的同学一个解决思路。如若其中有写的不好或者不对的地方也请不加不吝赐教,集思广益,共同进步。遇到...

javascript如何分割字符串(javascript切割字符串)

javascript如何分割字符串在JavaScript中,您可以使用字符串的`split()`方法来将一个字符串分割成一个数组。`split()`方法接收一个参数,这个参数指定了分割字符串的方式。如...

TextSplit函数的使用方法(入门+进阶+高级共八种用法10个公式)

在Excel和WPS新增的几十个函数中,如果按实用性+功能性排名,textsplit排第二,无函数敢排第一。因为它不仅使用简单,而且解决了以前用超复杂公式才能搞定的难题。今天小编用10个公式,让你彻底...

Python字符串split()方法使用技巧

在Python中,字符串操作可谓是基础且关键的技能,而今天咱们要重点攻克的“堡垒”——split()方法,它能将看似浑然一体的字符串,按照我们的需求进行拆分,极大地便利了数据处理与文本解析工作。基本语...

go语言中字符串常用的系统函数(golang 字符串)

最近由于工作比较忙,视频有段时间没有更新了,在这里跟大家说声抱歉了,我尽快抽些时间整理下视频今天就发一篇关于go语言的基础知识吧!我这我工作中用到的一些常用函数,汇总出来分享给大家,希望对...

无规律文本拆分,这些函数你得会(没有分隔符没规律数据拆分)

今天文章来源于表格学员训练营群内答疑,混合文本拆分。其实拆分不难,只要规则明确就好办。就怕规则不清晰,或者规则太多。那真是,Oh,mygod.如上图所示进行拆分,文字表达实在是有点难,所以小熊变身灵...

Python之文本解析:字符串格式化的逆操作?

引言前面的文章中,提到了关于Python中字符串中的相关操作,更多地涉及到了字符串的格式化,有些地方也称为字符串插值操作,本质上,就是把多个字符串拼接在一起,以固定的格式呈现。关于字符串的操作,其实还...

忘记【分列】吧,TEXTSPLIT拆分文本好用100倍

函数TEXTSPLIT的作用是:按分隔符将字符串拆分为行或列。仅ExcelM365版本可用。基本应用将A2单元格内容按逗号拆分。=TEXTSPLIT(A2,",")第二参数设置为逗号...

Excel365版本新函数TEXTSPLIT,专攻文本拆分

Excel中字符串的处理,拆分和合并是比较常见的需求。合并,当前最好用的函数非TEXTJOIN不可。拆分,Office365于2022年3月更新了一个专业函数:TEXTSPLIT语法参数:【...

站长在线Python精讲使用正则表达式的split()方法分割字符串详解

欢迎你来到站长在线的站长学堂学习Python知识,本文学习的是《在Python中使用正则表达式的split()方法分割字符串详解》。使用正则表达式分割字符串在Python中使用正则表达式的split(...

Java中字符串分割的方法(java字符串切割方法)

技术背景在Java编程中,经常需要对字符串进行分割操作,例如将一个包含多个信息的字符串按照特定的分隔符拆分成多个子字符串。常见的应用场景包括解析CSV文件、处理网络请求参数等。实现步骤1.使用Str...

因为一个函数strtok踩坑,我被老工程师无情嘲笑了

在用C/C++实现字符串切割中,strtok函数经常用到,其主要作用是按照给定的字符集分隔字符串,并返回各子字符串。但是实际上,可不止有strtok(),还有strtok、strtok_s、strto...