目录
一、生成器函数描述
二、简单生成器
generator元素的打印(g.next)
三、带yield语句的生成器
yield用例
yield from 委托给子生成器的语法
?四、generator使用
generator.__next__()
generator.send(value)
generator.throw(type[,?value[,?traceback]])
generator.close()
五、异步生成器 (未填坑)
参考资料:python3.7.8文档
生成器:一边循环一边计算的机制。
一、生成器函数描述
在一个函数体内使用 yield 表达式会使这个函数变成一个生成器。
当一个生成器函数被调用的时候,它返回一个迭代器,称为生成器。
然后这个生成器来控制生成器函数的执行。当这个生成器的某一个方法被调用的时候,生成器函数开始执行。这时会一直执行到第一个 yield 表达式,在此执行再次被挂起,给生成器的调用者返回?expression_list?的值。
挂起后,我们说所有局部状态都被保留下来,包括局部变量的当前绑定,指令指针,内部求值栈和任何异常处理的状态。
通过调用生成器的某一个方法,生成器函数继续执行。此时函数的运行就和 yield 表达式只是一个外部函数调用的情况完全一致。恢复后 yield 表达式的值取决于调用的哪个方法来恢复执行。 如果用的是?__next__()?(通常通过语言内置的?for?或是?next()?来调用) 那么结果就是?None. 否则,如果用?send(), 那么结果就是传递给send方法的值。
二、简单生成器
把一个列表生成式的[ ]改成( ),就创建了一个generator:
>>> L = [x * x for x in range(10)]>>> L[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]>>> g = (x * x for x in range(10))>>> g<generator object <genexpr> at 0x104feab40>
创建L和g的区别在于最外层的[]和(),L是一个list,而g是一个generator。
generator元素的打印(g.next) >>> g.__next__()0>>> g.__next__()1>>> g.__next__()4>>> g.__next__()9
加入for循环:
>>> g = (x * x for x in range(10))>>> for n in g:… print(n)…0149162536496481 三、带yield语句的生成器 yield用例
用斐波那契数列作为例子:
def fib1(max):??? n, a, b = 0, 0, 1??? while n < max:??????? print (b)??????? a, b = b, a + b??????? n = n + 1
从第一个元素开始,推算出后续任意元素,这样的逻辑与生成器非常类似。
使用带yield语句的生成器,代码变成:
def fib2(max):??? n, a, b = 0, 0, 1??? while n < max:??????? yield b??????? a, b = b, a + b??????? n = n + 1
?上面两个区别在于:
fib1是顺序执行的,遇到return语句或最后一行函数语句就返回。
generator函数(fib2)在每次调用__next__()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。(python2.x中为next())
用例:
>>> def odd():… print(‘step1’)… yield 1… print(‘step2’)… yield 3… print(‘step3’)… yield 5…>>> o = odd()>>> o.__next__()step11>>> o.__next__()step23>>> o.__next__()step35>>> o.__next__()Traceback (most recent call last): File “<stdin>”, line 1, in <module>StopIteration>>>
如上面的例子所示:
generator在执行过程中,遇到yield就中断,下次又继续执行。执行3次yield后,执行完毕,所以再次调用报错。?
对于上面的fib2,如果不设置终止条件,就会无限执行,所以设置了max,此外,通常不使用__next__()调美国高防vps用,而是使用for循环:
>>> def fib2(max):… n,a,b = 0,0,1… while n < max:… yield b… a,b = b,a+b… n = n+1…>>> for n in fib2(6):… print(n)…112358 yield from 委托给子生成器的语法
yield from表达式,允许生成器将其部分操作委托给另一个生成器。这允许将包含yield的一段代码分离出来并放置到另一个生成器中。此外,允许子生成器返回一个值,并且该值可用于委托生成器。
虽然主要设计用于委托给子生成器,但expression的yield实际上允许委托给任意的子迭代器。
对于简单的迭代器,iterable的yield本质上只是iterable中For item的缩写形式:
>>> def g(x):… yield from range(x, 0, -1)… yield from range(x)…>>> list(g(5))[5, 4, 3, 2, 1, 0, 1, 2, 3, 4]
?然而,与普通循环不同的是,yield from允许子生成器从调用范围直接接收发送和抛出的值,并向外部生成器返回一个最终值:
>>> def accumulate():… tally = 0… while 1:… next = yield… if next is None:… return tally… tally += next…>>> def gather_tallies(tallies):… while 1:… tally = yield from accumulate()… tallies.append(tally)…>>> tallies = []>>> acc = gather_tallies(tallies)>>> next(acc) # Ensure the accumulator is ready to accept values>>> for i in range(4):… acc.send(i)…>>> acc.send(None) # Finish the first tally>>> for i in range(5):… acc.send(i)…>>> acc.send(None) # Finish the second tally>>> tallies[6, 10] ?四、generator使用 generator.__next__()
开始一个生成器函数的执行或是从上次执行的 yield 表达式位置恢复执行。 当一个生成器函数通过?__next__()?方法恢复执行时,当前的 yield 表达式总是取值为?None。 随后会继续执行到下一个 yield 表达式,其?expression_list?的值会返回给?__next__()?的调用者。 如果生成器没有产生下一个值就退出,则将引发?StopIteration?异常。
此方法通常是隐式地调用,例如通过?for?循环或是内置的?next()?函数。
generator.send(value)
恢复执行并向生成器函数“发送”一个值。?value?参数将成为当前 yield 表达式的结果。?send()?方法会返回生成器所产生的下一个值,或者如果生成器没有产生下一个值就退出则会引发?StopIteration。 当调用?send()?来启动生成器时,它必须以?None?作为调用参数,因为这时没有可以接收值的 yield 表达式。
generator.throw(type[,?value[,?traceback]])
在生成器暂停的位置引发?type?类型的异常,并返回该生成器函数所产生的下一个值。 如果生成器没有产生下一个值就退出,则将引发?StopIteration?异常。 如果生成器函数没有捕获传入的异常,或引发了另一个异常,则该异常会被传播给调用者。
generator.close()
在生成器函数暂停的位置引发?GeneratorExit。 如果之后生成器函数正常退出、关闭或引发?GeneratorExit?(由于未捕获该异常) 则关闭并返回其调用者。 如果生成器产生了一个值,关闭会引发?RuntimeError。 如果生成器引发任何其他异常,它会被传播给调用者。 如果生成器已经由于异常或正常退出则?close()?不会做任何事。
>>> def echo(value=None):… print(“Execution starts when ‘next()’ is called for the first time.”)… try:… while True:… try:… value = (yield value)… except Exception as e:… value = e… finally:… print(“Don’t forget to clean up when ‘close()’ is called.”)…>>> generator = echo(1)>>> print(next(generator))Execution starts when ‘next()’ is called for the first time.1>>> print(next(generator))None>>> print(generator.send(2))2>>> generator.throw(TypeError, “spam”)TypeError(‘spam’,)>>> generator.close()Don’t forget to clean up when ‘close()’ is called. 五、异步生成器 (未填坑)
留坑。
13908186