1 python生成器yield函数和表达式
python生成器包括生成器函数和生成器表达式。
NO | 生成器 | 描述 |
---|---|---|
1 | 生成器函数 | 函数主体包含yield语句的函数,返回生成器对象,每次调用__next__(),执行到yield语句返回一个结果并停止执行后面的语句,再次调用从返回结果后面语句继续执行直到yield语句返回结果。 |
2 | 生成器表达式 | 圆括号编写的列表解析,返回生成器对象,每次调用__next__(),获取下一项生成器内容。通过list()和tuple()转为对应容器。 |
python生成器节省内存空间,因为返回生成器对象,而不是一次生成全部数据。
python生成器用于可以通过某种算法推算得到多个数据,不需一次生成全部数据,而是按需产生数据的场景。
1.1 python生成器函数yield
用法
def 函数名([入参]):
...
yield 表达式
...
描述
NO | 要点 | 描述 |
---|---|---|
1 | 组成 | python生成器函数是包含yield语句的函数。yield语句编译为生成器。 |
2 | 返回 | 调用生成器函数返回生成器对象,因为包含__next__()方法,所以是迭代器对象,支持迭代协议,可用于迭代环境。 |
3 | 执行 | 调用__next__()方法执行函数主体,运行到yield语句返回表达式结果,并且挂起函数不再执行后面语句;再次调用__next__()方法,回到yield语句,继续执行后面语句,再次运行到yiled语句返回结果,并且挂起函数;依次循环调用__next__()方法,直到最后一项完成,引发StopIteration异常。 |
示例
>>> def yieldF():
print('for开始前只执行一次')
for c in '梯阅线条':
print('yield前')
yield c
print('yield后')
print('for结束后只执行一次')
>>> y=yieldF()
>>> type(y)
<class 'generator'>
>>> '__next__' in dir(y)
True
>>> t=y.__next__()
for开始前只执行一次
yield前
#执行到yield语句,返回表达式结果,停止执行退出函数
>>> t #返回表达式结果
'梯'
>>> t=y.__next__()
#再次调用__next__,从yield后面一条语句开始执行,
yield后
#继续for循环,直到yield语句,返回表达式结果,停止执行退出函数
yield前
>>> t
'阅'
>>> t=y.__next__()
yield后
yield前
>>> t
'线'
>>> t=y.__next__()
yield后
yield前
>>> t
'条'
>>> t=y.__next__()
yield后
#for循环结束
for结束后只执行一次
#捕获到异常yield结束
Traceback (most recent call last):
File "<pyshell#47>", line 1, in <module>
t=y.__next__()
StopIteration
1.2 isgeneratorfunction()
描述
python函数isgeneratorfunction(函数名)用于判断一个函数是否为生成器函数。
示例
>>> def isgf(n):
for i in range(n):
yield i
>>> list(isgf(3))
[0, 1, 2]
>>> from inspect import isgeneratorfunction as isg
>>> isg(isgf)
True
>>> isg(isgf(3))
False
1.3 python存储yield值
描述
python通过list()或tuple()函数,将生成器函数yield表达式的值存储为列表或元组。
示例
>>> def yieldF():
print('for开始前只执行一次')
for c in '梯阅线条':
print('yield前')
yield c
print('yield后')
print('for结束后只执行一次')
>>> yl=list(y)
for开始前只执行一次
yield前
yield后
yield前
yield后
yield前
yield后
yield前
yield后
for结束后只执行一次
>>> yl
['梯', '阅', '线', '条']
1.4 python遍历yield项
描述
python的yield函数生成迭代器对象,支持迭代环境,比如通过for循环遍历yield迭代项。
示例
>>> def yieldF():
print('for开始前只执行一次')
for c in '梯阅线条':
print('yield前')
yield c
print('yield后')
print('for结束后只执行一次')
>>> y=yieldF()
>>> y=yieldF()
>>> for c in y:
print('c前')
print(c)
print('c后')
#for循环是迭代工具,会自动调用迭代对象的__next__()方法
#c为每次调用__next__()方法的yield返回表达式结果
#for循环自动调用__next__()方法,执行函数体,
#遇到yield,将表达式结果存储到c
for开始前只执行一次
yield前
c前
梯
c后
yield后
yield前
c前
阅
c后
yield后
yield前
c前
线
c后
yield后
yield前
c前
条
c后
yield后
for结束后只执行一次
1.5 python生成器的next方法
描述
python生成器g.next()方法,等效于next(g)。
调用next方法时,开始执行函数体,到yield语句暂停执行,返回表达式结果,再次调用next方法,从yield后面语句继续执行,直到yield语句或者遇到StopIteration异常停止。
示例
>>> def yieldF():
print('for开始前只执行一次')
for c in '梯阅线条':
print('yield前')
yield c
print('yield后')
print('for结束后只执行一次')
>>> y=yieldF()
>>> y.__next__()
for开始前只执行一次
yield前
'梯'
>>> next(y)
yield后
yield前
'阅'
>>> next(y)
yield后
yield前
'线'
>>> next(y)
yield后
yield前
'条'
>>> next(y)
yield后
for结束后只执行一次
Traceback (most recent call last):
File "<pyshell#25>", line 1, in <module>
next(y)
StopIteration
1.6 python生成器的send方法
用法
g.send(arg)
描述
python生成器对象的send()方法,和__next__()方法类似,可以返回下一个yield结果并暂停再继续。同时,send(arg)可以将arg发送给yield后面的变量。
(1) 第1次调用,用send(None),或__next__()方法。
第1次不送None,会报下面的错误,执行函数体时未设置变量接收入参。
TypeError**😗* can’t send non-None value to a just-started generator
(2) send(arg),返回yield结果,并将arg发送给yield后面的变量。
(3) 根据arg值停止生成器或做其他处理。
示例
>>> def yieldF():
for c in '梯阅线条':
print('yield前')
x=yield c
print(x)
print('yield后')
>>> y=yieldF()
>>> y.send('t')
Traceback (most recent call last):
File "<pyshell#44>", line 1, in <module>
y.send('t')
TypeError: can't send non-None value to a just-started generator
>>> y.send(None)
yield前
'梯'
>>> y.send('y')
y
yield后
yield前
'阅'
>>> next(y)
None
yield后
yield前
'线'
>>> y.send('t')
t
yield后
yield前
'条'
>>> y.send('t')
t
yield后
Traceback (most recent call last):
File "<pyshell#49>", line 1, in <module>
y.send('t')
StopIteration
1.7 python用yield生成斐波那契数列
描述
斐波那契数列是递归数列,第1和第2个数为1,第3个数开始,每一项都等于前两项之和。本示例通过yield生成斐那契数列。
示例
>>> def fib(max):
n,a,b=0,0,1
while n<max:
yield b
a,b=b,a+b
n=n+1
>>> list(fib(10))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
1.8 python生成器表达式
用法
(变量表达式 for 变量 in 迭代对象)
描述
python的生成器表达式放在圆括号内,返回一个生成器对象,每次调用next方法,返回表达式结果。
示例
>>> gexp=(x*2 for x in range(10) if x%2==1)
>>> next(gexp)
2
>>> next(gexp)
6
>>> next(gexp)
10
>>> next(gexp)
14
>>> next(gexp)
18
>>> next(gexp)
Traceback (most recent call last):
File "<pyshell#43>", line 1, in <module>
next(gexp)
StopIteration
#生成器的括号可以省略
>>> sum(x*2 for x in range(10) if x%2==1)
50
>>> sum((x*2 for x in range(10) if x%2==1))
50
>>> sorted(x*2 for x in range(10) if x%2==1)
[2, 6, 10, 14, 18]
#生成器的括号不可省略
>>> sorted((x*2 for x in range(10) if x%2==1),reverse=True)
[18, 14, 10, 6, 2]
1.9 python生成器为单迭代对象
描述
如果iter()返回迭代器为对象本身,则为一次迭代器。
python生成器函数和生成器表达式为一次迭代器,即单迭代对象。
多个迭代器会执行同一迭代器结果,任何迭代器完成,所有迭代器都完成。
必须重新生成迭代器进行使用。
示例
>>> g=(x*2 for x in '梯阅线条')
>>> iter(g) is g
True
>>> g1,g2=iter(g),iter(g)
>>> next(g1),next(g2)
('梯梯', '阅阅')
>>> next(g1),next(g2)
('线线', '条条')
>>> next(g1)
Traceback (most recent call last):
File "<pyshell#62>", line 1, in <module>
next(g1)
StopIteration
#多个迭代器会执行同一迭代器结果,任何迭代器完成,所有迭代器都完成。
>>> next(g2)
Traceback (most recent call last):
File "<pyshell#63>", line 1, in <module>
next(g2)
StopIteration
#必须重新生成迭代器进行使用。
>>> g=(x*2 for x in '梯阅线条')
>>> g1,g2=iter(g),iter(g)
>>> next(g1),next(g2)
('梯梯', '阅阅')