Python中的yield全方位解读

 更新时间:2023年08月21日 09:42:46   作者:软件测试技术  
这篇文章主要介绍了Python中的yield全方位解读,在 Python 中,使用了 yield 的函数被称为生成器,跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器,需要的朋友可以参考下

Python中的yield

关于 yield 看了忘,忘了看,零零散散的总是理解不透彻。今天彻底记录下,带大家一探 yield 到底是什么?

关于生成器概念的解释,摘自菜鸟教程解释:

在 Python 中,使用了 yield 的函数被称为生成器(generator)。 跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。 在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。 调用一个生成器函数,返回的是一个迭代器对象。

网上例子很多,所有例子一开始就是这样的代码:

# !!!这种代码 建议别看,因为以我亲身经历,初次理解生成器,看这样的代码根本看不懂的~
def evenNumber(max):
    n = 0
    while n < max:
        yield n
        n += 2
for i in evenNumber(10):
    print(i)

一会儿我把上述代码重新写下。

在此之前,大家还是需要掌握什么是generator(生成器)。

generator(生成器)

最简单的创建一个生成器的方式,只要把一个列表生成式的 [] 改成 () ,就创建了一个generator:

List  = [i*2 for i in range(10)]
print(List)
#[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
g = (x*2 for x in range(10))
print(g)
#<generator object <genexpr> at 0x000001CBA42F3C10>

生成器(generator)能够迭代的关键是它有一个next()方法,工作原理就是通过重复调用next()方法,直到捕获一个异常。试一下:

g = (x*2 for x in range(10))
print(g.__next__())
# 0
print(g.__next__())
# 2
print(g.__next__())
# 4
#... ...

第二种方法就是, 如果一个函数中包含 yield 关键字,那么这个函数就不再是一个普通函数,而是一个generator。调用函数就是创建了一个生成器(generator)对象。

着重讲一下第二种方法,先看代码,为了便于理解,我不写循环,写一个生成器函数:

def gen_example():
    print ('第1次执行啦~,还没到第一个yield!')
    yield '我是第1个遇见的yield,你遇到我就要返回'
    print ('第2次执行啦~,还没到第二个yield')
    yield '我是第2个遇见的yield,你遇到我就要返回'
    print ('第3次执行啦,我运行完 函数就执行完毕啦~')
for i in gen_example():
    print(i)
    print("--------分割线--------")

执行结果:

第1次执行啦~,还没到第一个yield!
我是第1个遇见的yield,你遇到我就要返回
--------分割线--------
第2次执行啦~,还没到第二个yield
我是第2个遇见的yield,你遇到我就要返回
--------分割线--------
第3次执行啦,我运行完 函数就执行完毕啦~

过程详解:

第一次for 循环执行到yield结束 ,只执行了这两句代码:

在这里插入图片描述

第二次循环 是从上一次的yield结束地方开始执行, 到下一个yield结束(一定要多读几遍理解哦):

在这里插入图片描述

第三次循环是,从第二次遇见的yield结束地方开始执行,一直到下一个yield结束(没有yield,自动执行结束)

在这里插入图片描述

通过上述规律我们不难发现,yield相当于 return 返回一个值,并且记住这个返回的位置,下次迭代时,代码从yield的下一条语句开始执行!

为了验证这个规律 我把本文开头的代码 重新写下,用更容易懂的方式:

def evenNumber(max):
    n = 0
    while n < max:
        yield n
        print("第二次是从这里开始的")
        n += 2
        print(f"n在第二次是{n}")
for i in evenNumber(2):
    print(i)
    print("--------分割线--------")

执行结果:

0
--------分割线--------
第二次是从这里开始的
n在第二次是2

输出:0, 是怎么得到的呢?函数第一次执行,遇到yield 就返回,所以此时就打印0。

在这里插入图片描述

第二次是从这里开始的,n在第二次是2 这又是怎么得到的呢?执行yield后面的这部分,然后又进入循环,while循环条件都不满足,执行结束。

实际第二次没有返回值。如果你细心点就会发现,第二次输出都没有分割线的内容:

在这里插入图片描述

在这里插入图片描述

既然 第二次打印都终止了,为什么没报错? 好问题!因为调用next()来执行生成器则会报错,如果使用for循环遍历,for循环会自动捕获该异常,直接停止遍历。

def evenNumber(max):
    n = 0
    while n < max:
        yield n
        print("第二次是从这里开始的")
        n += 2
        print(f"n在第二次是{n}")
g = evenNumber(2)
print(g.__next__())
print(g.__next__())

执行结果,调用next方法就会报错:

0
第二次是从这里开始的
n在第二次是2
Traceback (most recent call last):
  File "test.py", line 17, in <module>
    print(g.__next__())
StopIteration
***Repl Closed***

所以,就印证了我们的结论~! 现在来看一些简单的生成器函数的例子,是不是就一下懂了。

如果看到这里还是没懂 ,留言吧,我会好好反思我自;

留个小作业 大家可以试试分析下斐波那契数列的过程。

def fab(max): 
    n, a, b = 0, 0, 1 
    while n < max: 
        yield b     
        a, b = b, a + b 
        n = n + 1
for n in fab(5): 
    print n

其它补充

如何判断是不是 生成器函数?

使用 isgeneratorfunction 判断函数是否是 generator 函数

from inspect import isgeneratorfunction 
print(isgeneratorfunction(fab) )
#True

为什么生成器函数中的return 不能返回值?

先看代码:

def evenNumber(max):
    n = 0
    while n < max:
        yield n
        print("第二次是从这里开始的")
        n += 2
        print(f"n在第二次是{n}")
        return 10
for i in evenNumber(10):
    print(i)
    print("--------分割线--------")

执行结果:

0
--------分割线--------
第二次是从这里开始的
n在第二次是2
***Repl Closed***

为什么 我的return 的值 没有在最后一次打印出来呢? 在官方文档中是这样解释的:

在这里插入图片描述

python生成器函数中return 的作用就是终止生成器。

表示生成器运行完成了,可以结束了。然后生成器会抛出一个StopIteration的异常。

而for循环能够检测到这个异常,于是结束循环,也不报错。但是__next__()就会报错哦~

到此这篇关于Python中的yield全方位解读的文章就介绍到这了,更多相关Python中的yield内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python 权限控制模块 Casbin

    Python 权限控制模块 Casbin

    这篇文章主要介绍了Python 权限控制模块 Casbin,Casbin是一个强大的、高效的开源访问控制框架,其权限管理机制支持多种访问控制模型,更多相关内容感兴趣的朋友可以参考下面文章内容
    2022-06-06
  • typing.Dict和Dict的区别及它们在Python中的用途小结

    typing.Dict和Dict的区别及它们在Python中的用途小结

    当在 Python 函数中声明一个 dictionary 作为参数时,我们一般会把 key 和 value 的数据类型声明为全局变量,而不是局部变量。,这篇文章主要介绍了typing.Dict和Dict的区别及它们在Python中的用途小结,需要的朋友可以参考下
    2023-06-06
  • 详解基于python的图像Gabor变换及特征提取

    详解基于python的图像Gabor变换及特征提取

    这篇文章主要介绍了基于python的图像Gabor变换及特征提取,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2020-10-10
  • 如何使用五行Python代码轻松实现批量抠图

    如何使用五行Python代码轻松实现批量抠图

    简单来说,抠图就是将照片的主体人或物品从图片中抠出来,以便贴到别处使用,下面这篇文章主要给大家介绍了关于如何使用五行Python代码轻松实现批量抠图的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2022-04-04
  • 三分钟教会你用Python+OpenCV批量裁剪xml格式标注的图片

    三分钟教会你用Python+OpenCV批量裁剪xml格式标注的图片

    最近学习网络在线课程的过程中,为了方便课后复习,使用手机截取了大量的图片,下面这篇文章主要给大家介绍了如何通过三分钟教会你用Python+OpenCV批量裁剪xml格式标注图片的相关资料,需要的朋友可以参考下
    2022-01-01
  • PyCharm Python Console中文输出乱码问题及解决

    PyCharm Python Console中文输出乱码问题及解决

    这篇文章主要介绍了PyCharm Python Console中文输出乱码问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • python中调试或排错的五种方法示例

    python中调试或排错的五种方法示例

    这篇文章主要给大家介绍了关于python中调试或排错的五种方法,文中通过示例代码介绍的非常详细,对大家学习或者使用Python具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-09-09
  • python文件读写操作小结

    python文件读写操作小结

    python文件对象提供了三个“读”方法: read()、readline() 和 readlines(),每种方法可以接受一个变量以限制每次读取的数据量,这篇文章主要介绍了python文件读写小结,需要的朋友可以参考下
    2022-02-02
  • 5个Python中实现文字转语音模块的使用讲解

    5个Python中实现文字转语音模块的使用讲解

    这篇文章主要为大家详细介绍了5个Python中实现文字转语音模块的使用,文中的示例代码讲解详细,对我们深入掌握Python有一定的帮助,需要的可以参考下
    2023-11-11
  • Pandas实现数据类型转换的一些小技巧汇总

    Pandas实现数据类型转换的一些小技巧汇总

    这篇文章主要给大家汇总介绍了关于Pandas实现数据类型转换的一些小技巧,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-05-05

最新评论