再说generator生成器

2021年2月22日 / 6次阅读 / Last Modified 2021年2月22日

python有一个生成器概念,代码每当执行到yield的时候,函数就返回,并且python解释器记住了yield这一行的位置,下次还能从这一行后面开始继续执行。这种特性恐怕只有解释性的语言才有。(专业术语叫挂起,唤醒)

这是之前的一篇生成器blog。生成器跟python的coroutine(协程)的实现有关,本文先总结生成器的一些其它基础特性。

>>> def test():
...   for i in ran
...     yield i
...
>>>
>>> f = test()
>>> next(f)
0
>>> next(f)
1
>>> next(f)
2
>>> next(f)
3
>>> g = test()
>>> g.send(None)
0
>>> g.send(None)
1
>>> g.send(None)
2
>>> g.send(None)
3

不仅能用next调用生成器,生成器还自带一个send函数,效果与next似乎一样,触发生成器的执行,并停留在yield那一行。

send函数是什么意思?它可以向已经开始执行的生成器内部传一个参数,看如下代码:

>>> def test2():
...   for i in range
...     j = yield i
...     print('j = ',j)
...
>>> f = test2()
>>> next(f)
0
>>> next(f)
j =  None
1
>>> next(f)
j =  None
2
>>> next(f)
j =  None
3
>>> g = test2()
>>> g.send(None)
0
>>> g.send('123')
j =  123
1
>>> g.send('1234')
j =  1234
2
>>> g.send('12345')
j =  12345
3
>>> h = test2()
>>> next(h)
0
>>> h.send('666')
j =  666
1
>>>

yield i变成了赋值语句的一部分,它除了保持原语义之外,还成了能够接收send函数传入参数的方式。从上面代码能够看出,可以用next或者send(None)启动生成器,然后send函数就开发发挥传入参数的威力了!

close函数停止生成器。

>>> def test3():
...   for i in range(4):
...     try:
...       yield i
...     except Exception as e:
...       print(repr(e))
...
>>> f = test3()
>>> next(f)
0
>>> next(f)
1
>>> f.close()
>>> next(f)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

调用生成器的close函数后,就不能再执行了,会抛出StopIteration异常。我看到有些资料上说,生成器内部在close的时候,会有GeneratorExit一行,但以上代码没有捕获到。

throw函数,向生成器内扔异常

还是上面的test3函数,我们换一种方式来执行:

>>> g = test3()
>>> next(g)
0
>>> next(g)
1
>>> g.throw(ValueError('abcde'))
ValueError('abcde')
2
>>> g.throw(ValueError('12345'))
ValueError('12345')
3
>>> g.throw(IndexError('abcde12345'))
IndexError('abcde12345')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

调用throw函数,可以向生成器内扔异常,但是注意,它同样也在触发生成器的新一轮的执行!

以上就是python生产等对象的3个有趣的方法,send,close,throw。

生成器可以嵌套,还有一个yield from语句:

def reader():
    # 模拟从文件读取数据的生成器,for表达式可以简写为:yield from range(4)
    #for i in range(4):
    #    yield i
    yield from range(4)
    
def reader_wrapper():
    yield from reader()
    
wrap = reader_wrapper()
for i in wrap:
    print(i)

-- EOF --

本文链接:https://www.pynote.net/archives/3544

相关文章

    留言区

    《再说generator生成器》有1条留言

    邮箱地址不会被公开。 必填项已用*标注

    • 麦新杰

      yield 在这里就像一扇门,可以把一件东西从这里送出去,也可以把另一件东西拿进来。 [回复]


    前一篇:
    后一篇:

    More


    ©Copyright 麦新杰 Since 2019 Python笔记

    go to top