python3-生成器
目录
一、生成器概念
通过列表生成式,我们可以直接创建一个列表 ,但是 受到内存限制,列表容量肯定是有限 。如果要创建多个元素的列表,但是只访问前几个元素时,那后面元素空间都浪费了。因此,生成器 generator 就很有必要了, 它采用一边循环一边计算的机制 ,在循环的过程中不断推算出后续元素。这就是所谓的延迟操作,在需要的时候产生结果,而不是立即产生结果
1、生成器表达式
t=(x*x for x in range(10))
print(t)
输出结果:
D:\python3.7\python\python3.exe D:/learn/pytest/learn.py
<generator object <genexpr> at 0x00000000021687C8>
生成器是一个对象,用的是()。用[]就等于创建一个列表
2、生成器函数
定义generator函数:如果一个函数定义中包含yield
关键字,那么这个函数就不再是一个普通函数,而是一个generator
def count(n):
yield n**2
for i in range(5):
print(count(i).__next__())
输出结果:
D:\python3.7\python\python3.exe D:/learn/pytest/learn.py
0
1
4
9
16
二、yield
斐波那契数列
def f(max):
n,a,b=0,0,1
while n<max:
yield b
a,b=b,a+b
n=n+1
return 'end'
f=f(5)
for i in range(5):
print(f.__next__())
输出结果:
1
1
2
3
5
generator和函数的执行流程不一样。函数是顺序执行,遇到return
语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()
的时候执行,遇到yield
语句返回,再次执行时从上次返回的yield
语句处继续执行。
1.和return相似,返回值。
2.暂停迭代,直到调用下一个next()方法。先返回再暂停。
3.调用的时候返回生成器对象。
假如yield后面紧接着一个数据,就会把数据返回,作为next()函数或者for ...in...迭代出的下一个值。
三、send()
send用于传递参数,实现与生成器交互,send的参数其实就是唤醒yield 语句的返回值
def test():
n=0
while n<4:
temp=yield n*2
n=n+1
print(temp)
t=test()
print(t.send(None))
print(t.send('hello'))
print(t.send('hello'))
输出结果:
0
hello
2
hello
4
注意: 第一次运行只能使用next或者send(None) , send的作用相当于使生成器继续运行,并且传递的参数为yield的返回值(程序中即temp的值)
赋值:
def h():
print('start')
x=yield 'first time'
print(x)
y=yield 'second time'
print(y)
a=h()
print(a.__next__())
print(a.send('----'))
输出结果:
start
first time
----
second time
四、throw()
throw()函数的作用首先是抛给生成器一个异常,然后如果生成器能处理掉异常的话,throw方法接着迭代一次取得返回值,注意,捕获异常是在上一次迭代中断的位置捕获,因为每次生成器运行的时候,都是从上一次发生yield中断的地方开始运行,所以抛来的异常发生在这个地方,捕获当然也要在这个地方
def gen():
n=0
while n<5:
try:
yield n * 2
n = n + 1
except Exception as e:
print('error')
g=gen()
print(g.__next__())
print(next(g))
print(g.throw(Exception, "download error"))
输出结果:
0
2
error
2
五、close()
生成器对象的close方法会在生成器对象方法的挂起处抛出一个GeneratorExit异常。GeneratorExit异常产生后,系统会继续把生成器对象方法后续的代码执行完毕
def gen_close():
try:
yield 1
print('close after yield')
yield 2
except GeneratorExit:
print("Generator error caught")
print("end")
gen1 = gen_close()
print(gen1.__next__())
gen1.close()
输出:
1
Generator error caught
end
如果在close()方法后在执行next(),就会触发StopIteration错误
需要注意的是,GeneratorExit异常的产生意味着生成器对象的生命周期已经结束。因此,一旦产生了GeneratorExit异常,生成器方法后续执行的语句中,不能再有yield语句,否则会产生RuntimeError。请看下面的例子。
def gen_close():
try:
yield 1
print('close after yield')
yield 2
except GeneratorExit:
print("Generator error caught")
yield 3
gen1 = gen_close()
print(gen1.__next__())
gen1.close()
输出结果:
1
Generator error caught
Traceback (most recent call last):
File "D:/learn/pytest/learn.py", line 84, in <module>
gen1.close()
RuntimeError: generator ignored GeneratorExit