小门板儿

Menu

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

参考来源:https://www.cnblogs.com/rainbow-ran/p/12201890.html

https://blog.csdn.net/hedan2013/article/details/72811117

— 于 共写了2634个字
— 标签:

评论已关闭。