python yield函数_python yield浅析

本文详细介绍了Python中的生成器,包括什么是迭代器,yield的作用,生成器执行流程,以及如何判断生成器函数。重点讲解了yield如何在运行时生成值,节省内存并提高效率,通过实例展示了生成器的工作原理。
摘要由CSDN通过智能技术生成

在python(本文python环境为python2.7)中,使用yield关键字的函数被称为generator(生成器)。故为了了解yield,必然先要了解generator,而了解generator之前,我们先要了解一下迭代。

递归和迭代

聊迭代之前,我们也顺带简单了解一下递归:

1,递归:程序调用自身的编程技巧称为递归

应用案例:求n的阶乘

def factorial(n) :

if n == 1 :

return 1 #递归结束

return n * factorial(n - 1) #问题规模减1,递归调用

2,迭代:迭代是程序中对一组指令(或一定步骤)的重复

应用案例:读取列表中的每个元素

mylist = [1, 2, 3]

for i in mylist :

print(i)

2.1,可迭代对象是什么?

如上所示code使用了迭代的方法,而列表mylist是一个可迭代对象。当你建立了一个列表,你可以逐项地读取这个列表,而这个创建的列表就是一个可迭代对象。

2.2,迭代器是什么?

迭代器(iterator)是访问集合内元素的一种方式,提供了一种遍历类序列对象的方法。对于一般的序列,利用索引从0一直迭代到序列的最后一个元素。对象从集合的第一个元素开始访问,直到所有的元素都被访问一遍后结束。对于字典、文件、自定义对象类型等,可以自定义迭代方式,从而实现对这些对象的遍历。总之,迭起器就是定义了对对象进行遍历的方式。

而实现了迭代器规范的对象就是迭代器,规范如下:

1,实现了魔法方法 iter(),返回一个迭代对象,这个对象有一个next()方法,

2,实现 next() 方法,返回当前的元素,并指向下一个元素的位置,当前位置已经没有元素的时候,抛出StopIteration异常。

python for循环的时候,首先对循环对象实现迭代器包装,返回一个迭代器对象,然后每循环一步,就调用哪个迭代器对象的next方法,循环结束的时候,自动处理了StopIteration这个异常。for循环是对迭代器进行迭代的语法糖。

python中使用iter函数来生成一个迭代器:

>>> t = [1, 2, 3]

>>> it = iter(t)

>>> it.next()

1

生成器和yield

生成器是什么?

生成器也是一种迭代器,但是你只能对其迭代一次。这是因为它们并没有把所有的值存在内存中,而是在运行时生成值,这样能节省大量内存空间并且提高效率。

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。

2,yield是什么?

yield是python内部的一个关键字,内部实现支持了迭代器协议,同时yield内部是一个状态机,维护着挂起和继续的状态,yield关键字返回的就是一个生成器。

3,生成器的执行流程

代码样例:

>>> def fab(max):

... n, a, b = 0, 0, 1

... while n < max:

... yield b

... a, b = b, a + b

... n = n + 1

...

...

>>> f = fab(5)

>>> f.next()

1

>>> f.next()

1

>>> f.next()

2

>>> f.next()

3

>>> f.next()

5

>>> f.next()

Traceback (most recent call last):

File "", line 1, in

StopIteration

>>>

通过结果可以看到:

当调用生成器函数的时候,函数只是返回了一个生成器对象,并不执行。

当next()方法第一次被调用的时候,生成器函数才开始执行,执行到yield语句处停止,next()方法的返回值就是yield语句处的参数

当继续调用next()方法的时候,函数将接着上一次停止的yield语句处继续执行,并到下一个yield处停止,如果后面没有yield就抛出StopIteration异常

4,如何判断一个函数是否是一个特殊的 generator 函数?可以利用 isgeneratorfunction 判断:

>>> from inspect import isgeneratorfunction

>>> isgeneratorfunction(fab)

True

结论

一个带有 yield 的函数就是一个 generator,它和普通函数不同,生成一个 generator 看起来像函数调用,但不会执行任何函数代码,直到对其调用 next()(在 for 循环中会自动调用 next())才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。

yield 的好处是显而易见的,把一个函数改写为一个 generator 就获得了迭代能力,比起用类的实例保存状态来计算下一个 next() 的值,不仅代码简洁,而且执行流程异常清晰。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值