先看个例子:
my_tuple = (x**x for x in range(4))
my_tuple
<generator object <genexpr> at 0x00000210B3244CF0>
yield
yielf定义
在Python中定义生成器必须使用关键字yield
。它作为一个关键字,是生成器的标志。
- 有了yield关键字的函数说明是个生成器对象,这个生成器对象也是迭代器。
- 语句在调用的时候返回相应的值
- 含有
yield
关键字语句的函数称之为生成器。生成器是一种用普通函数语法定义的迭代器。 - 普通函数(包含
yield
)--->生成器--->迭代器
def func():
yield 0
yield 1
yield 2
>>func
<function __main__.func()>
>>type(func)
function
>>g = func()
>>g
<generator object func at 0x00000210B32447C8>
>>type(g)
generator
查看生成器g的具体方法:
>>dir(g)
['__class__',
'__del__',
'__delattr__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__iter__',
'__le__',
'__lt__',
'__name__',
'__ne__',
'__new__',
'__next__',
'__qualname__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'close',
'gi_code',
'gi_frame',
'gi_running',
'gi_yieldfrom',
'send',
'throw']
yield执行
通过执行上面的g生成器对象的next()方法,查看运行过程:
image.png
g = func():
引用一个生成器对象g.__next__():
生成器开始执行,遇到第一个yield
语句返回其值0,并且暂停执行(称之为挂起)g.__next__():
从上次的位置开始,继续执行,返回值1,挂起g.__next__():
从上次的位置开始,继续执行,返回值2,挂起g.__next__():
从上次的位置开始,继续执行,但是后面没有可执行的对象,故报错。
yield vs return
函数返回值由一个return,那么yield和return有什么区别呢?
return
- 一般函数中,return后面的语句不会执行
- 调用函数立刻执行函数体内的语句
def return_func(n):
print("hell python")
while n > 0:
print("before return")
return n
n -= 1
print("after return")
>>res = return_func(3)
hell python
before return
image.png
yield
- 调用函数不会立即执行函数体内的语句
- 作为生成器的函数,有了
yield
,会挂起。 - 有了
yield
就是生成器,就有__next__()
方法
image.png
利用yield生成斐波那契数列
def fibs(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n += 1
if __name__ == "__main__":
f = fibs(10)
for i in f:
print(i)
1
1
2
3
5
8
13
21
34
55
n是否满足while条件a(前)b(前)a(后)b(后)
0是0111
1是1112
2是1223
3是2335
4是3558
5是58813
6是8131321
7是13212134
8是21343455
9是34555589