Learn Python 3: 生成器中的 yield 机制

2019-03-09  本文已影响0人  SheHuan

开始前先认识下生成器,即generator

创建列表可以使用列表生成式:

>>>l = [v**2 for v in range(1,10)]
>>>l
[1, 4, 9, 16, 25, 36, 49, 64, 81]

但如果要创建的列表有百万甚至千万个元素,用到的元素只有前几个,考虑到内存的因素我们肯定不能直接创建,生成器就很好的解决了这个问题,生成器不会直接创建整个列表,而是在迭代的过程中推算出每个元素的值,是惰性的。

把列表生成式的[]的换成()就是一个简单的生成器:

>>>g = (v**2 for v in range(1,10))
>>>g
<generator object <genexpr> at 0x000000000220F1A8>

要取出生成器每一个元素可以通过next()函数:

0
当没有元素可取时会抛出一个StopIteration异常,需要自行捕获处理。
如果有成千上万个元素,一直next()当然不行了,由于生成器是可迭代的,可以用for循环来处理,还有一个好处就是不用考虑StopIteration异常:
>>>for v in g:
...    print(n)

可以使用isinstance()判断一个对象是否是可迭代对象(Iterable):

>>>from collections import Iterable
>>>isinstance(g, Iterable)
True

除了用()创建生成器,如果一个函数定义中有yield关键字,则这个函数也是一个生成器:

def test():
    print('step-1')
    yield 1
    print('step-2')
    yield 2
    print('step-3')
    yield 3
>>>g = test()
>>>g
<generator object test at 0x00000000027EF1A8>

所以同样可以用next()或者for循环来迭代它。当每次执行next(g)时,生成器函数遇到yield表达式就会中断并返回yield表达式后边的参数值,例如:

>>>next(g)
step-1
1

再次执行时从上次返回的yield表达式处继续执行,返回下一个yield表达式的参数值,直到再无yield表达式参数可返回并抛出异常:

>>>next(g)
step-2
2
>>>next(g)
step-3
3

除了next()外,还有一个很重要的函数send(),它和next()作用类似,但是send()可以发送值给对应的yield表达式,我们之前执行next(g)就相当于g.send(None)

注意第一次调用next()send(None)相当于启动生成器,不能使用send()发送一个非None的值,否则会出错的(TypeError: can't send non-None value to a just-started generator),因为还没有yield表达式来接收这个值。

那么启动生成器后,用send()发送的值如何被生成器中yield表达式接收呢?先修改上边的生成器函数:

def test():
    print('step-1')
    x = yield 1
    print(x)
    print('step-2')
    y = yield 2
    print(y)
    print('step-3')
    x = yield 3

我们打印了前两个yield表达式的值。接下来通过send()方式先启动生成器:

>>>g = test()
>>>g.send(None)
step-1
1

仅仅是打印了提示语和返回了第一个yield表达式的参数值。再继续执行:

>>>g.send('hello')
hello
step-2
2

可以看到先打印了用send()发送的值,然后是提示语和第二个yield表达式的参数值,所以这次send()发送的值被第一个yield表达式接收了,即yield 1表达式被赋值为hello,即x = 'hello'。再继续执行:

>>>g.send('world')
world
step-3
3

即第二个yield 2表达式被赋值为world,并返回了第三个yield表达式的参数值。

所以每次执行send()next()只是返回了对应yield表达式的参数值,其实对应表达式并未执行,直到下次再执行send()next()才会执行上次返回参数的yield表达式,所谓的执行yield表达式就是给其赋值,并返回下一个yield表达式的参数值!

上一篇下一篇

猜你喜欢

热点阅读