视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Python生成器定义与简单用法实例分析
2020-11-27 14:21:48 责编:小采
文档

B、yield关键字

在一个函数定义中包含yield关键字,则这个函数就不再是一个普通的函数,而是一个生成器(generator)

[说明]:yield指令可以暂停一个函数并返回其中间结果,使用该指令的函数将保存执行环境,并在必要时恢复

def fib(max):
 n,a,b=0,0,1
 while n<max:
 #print(b)
 yield b
 a,b=b,a+b
 n+=1
 return 'done'
f=fib(6)
print(f)

运行结果:

<generator object fib at 0x0000000002553150>

[注]:普通函数和变成生成器的函数的不同:

普通函数是顺序执行的,遇到return或是最后一行函数语句就返回。而变成生成器的函数在每次调用__next__()方法时执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行

f=fib(6)
print(f)
print(f.__next__())
print(f.__next__())
print('暂停一下')
print(f.__next__())
print(f.__next__())

运行结果:

<generator object fib at 0x00000000025631A8>
1
1
暂停一下
2
3

三、生成器方法(参考:伯乐在线)

1.close()方法:手动关闭生成器函数,后面的调用会直接返回StopIteration异常

def func():
 yield 1
 yield 2
 yield 3
g=func()
g.__next__()
g.close() #手动关闭生成器
g.__next__() #关闭后,yield 2和yield 3语句将不再起作用

运行结果:

Traceback (most recent call last):
File "E:py3DemoHellogeneratorDemo.py", line 9, in <module>
g.__next__() #关闭后,yield 2和yield 3语句将不再起作用
StopIteration

2.__next__()方法:返回生成器的下一次调用

def func():
 n=1
 for i in range(3):
 yield n
 n+=1
c=func()
a1=c.__next__()
a2=c.__next__()
a3=c.__next__()

[流程解释]:

对于普通的生成器,第一个__next__()方法的调用相当于启动生成器,此时会从生成器函数的第一行开始执行,直到第一次执行完yield语句(第四行)后,跳出生成器函数。

当调用第二个__next__()方法后,会重新进入生成器函数,并从yield语句的下一条语句(第五行)开始执行,直到重新运行到yield语句,执行后再次跳出生成器函数。

后面的__next__()方法调用以此类推

3.send()方法:接受外部传入的一个变量,并根据变量内容计算结果返回到生成器函数中

[注]:

(1)send()方法和__next__()方法相似,区别在于send()方法可以传递给yield表达式值,而__next__()方法不能传递特定的值,只能传递None给yield表达式,因此可以将generator.__next__()理解为generator.send(None)

(2)第一次调用生成器函数时,必须使用__next__()语句或是send(None),不能使用send发送一个非None的值给生成器函数,否则会出错,因为没有yield语句来接收这个值

def gen():
 value=0
 while True:
 receive=yield value
 if receive=='end':
 break
 value='Got:%s' %receive
g=gen()
print(g.__next__()) #或是print(g.send(None)),从而启动生成器
print(g.send('aaa'))
print(g.send(3))
print(g.send('end'))

运行结果:

0
Got:aaa
Got:3
Traceback (most recent call last):
File "E:py3DemoHellogeneratorDemo.py", line 13, in <module>
print(g.send('end'))
StopIteration

[流程解释]:

a.通过g.send(None)或g.__next__()启动生成器函数,并执行到第一个yield语句结束的位置并将函数挂起。此时执行完了yield语句,但是没有给receive赋值,因此yield value会输出value的初始值0

b.g.send('aaa')先将字符串‘aaa'传入到生成器函数中并赋值给receive,然后从yield语句的下一句重新开始执行函数(第五句),计算出value的值后返回到while头部开始新一轮的循环,执行到yield value语句时停止,此时yield value会输出‘Got:aaa',然后挂起

c.g.send(3)重复步骤b,最后输出结果为‘Got:3'

d.g.send('end')会使程序执行break然后跳出循环,从而函数执行完毕,得到StopIteration异常

4.throw()方法:向生成器发送一个异常。

def gen():
 while True:
 try:
 yield 'normal value' #返回中间结果,此处的yield和return的功能相似
 yield 'normal value2'
 print('I am here')
 except ValueError:
 print('We got ValueError')
 except Exception:
 print('Other errors')
 break
g=gen()
print(g.__next__())
print(g.throw(ValueError))
print(g.__next__())
print(g.throw(TypeError))

运行结果:

Traceback (most recent call last):
File "E:py3DemoHellogeneratorDemo.py", line 17, in <module>
print(g.throw(TypeError))
StopIteration
normal value
We got ValueError
normal value
normal value2
Other errors

[解释]:

a.print(g.__next__())会输出normal value,并停在yield 'normal value2'之前

b.由于执行了g.throw(ValueError),所以回跳过后续的try语句,即yield ‘normal value2'不会执行,然后进入到except语句,打印出‘We got ValueError'。之后再次进入到while语句部分,消耗一个yield,输出normal value

c.print(g.__next__())会执行yield ‘normal value2'语句,并停留在执行完该语句后的位置

d.g.throw(TypeError)会跳出try语句,因此print('I am here')不会被执行,然后打印‘Other errors',并执行break语句跳出while循环,然后到达程序结尾,打印StopIteration异常的信息

四、生成器的运用

import time
def consumer(name):
 print('%s准备吃包子啦!' %name)
 while True:
 baozi=yield #接收send传的值,并将值赋值给变量baozi
 print('包子[%s]来了,被[%s]吃了!' %(baozi,name))
def producer(name):
 c1=consumer('A') #把函数变成一个生成器
 c2=consumer('B')
 c1.__next__()#调用这个方法会走到yield处暂时返回
 c2.__next__()
 print('开始准备做包子啦!')
 for i in range(10):
 time.sleep(1)
 print('做了一个包子,分成两半')
 c1.send(i)
 c2.send(i)
producer('Tomwenxing')

运行结果:

A准备吃包子啦!
B准备吃包子啦!
开始准备做包子啦!
做了一个包子,分成两半
包子[0]来了,被[A]吃了!
包子[0]来了,被[B]吃了!
做了一个包子,分成两半
包子[1]来了,被[A]吃了!
包子[1]来了,被[B]吃了!
做了一个包子,分成两半
包子[2]来了,被[A]吃了!
包子[2]来了,被[B]吃了!
做了一个包子,分成两半
包子[3]来了,被[A]吃了!
包子[3]来了,被[B]吃了!
做了一个包子,分成两半
包子[4]来了,被[A]吃了!
包子[4]来了,被[B]吃了!
做了一个包子,分成两半
包子[5]来了,被[A]吃了!
包子[5]来了,被[B]吃了!
做了一个包子,分成两半
包子[6]来了,被[A]吃了!
包子[6]来了,被[B]吃了!
做了一个包子,分成两半
包子[7]来了,被[A]吃了!
包子[7]来了,被[B]吃了!
做了一个包子,分成两半
包子[8]来了,被[A]吃了!
包子[8]来了,被[B]吃了!
做了一个包子,分成两半
包子[9]来了,被[A]吃了!
包子[9]来了,被[B]吃了!

下载本文
显示全文
专题