理解一下yield关键字

笔记

yield是一个生成器关键字,类比return,用来处理无限序列的返回值。这是我之前对yield的全部理解。

换言之,我对yield只有一个浅显的认知,,用它来代替return 的函数,会自动变成一个生成器函数,在轮循的时候不断调用,如:

In [1]: def simple_generator_function():
   ...:     yield 1
   ...:     yield 2
   ...:     yield 3
   ...:     

In [2]: simple_generator_function()	#可以看到该函数定义了一个生成器的对象
Out[2]: <generator object simple_generator_function at 0x7fa90d48ee60>

In [3]: for value in simple_generator_function():
   ...:     print(value)
   ...:     
1
2
3

for循环这个简单的生成器,可以每轮读一个值。

也可以用next调用生成器,生成下一个值,如


In [4]: our_generator = simple_generator_function()

In [5]: next(our_generator)
Out[5]: 1

In [6]: next(our_generator)
Out[6]: 2

In [7]: next(our_generator)
Out[7]: 3

In [8]: next(our_generator)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-8-57a7077cf65e> in <module>()
----> 1 next(our_generator)

StopIteration: 

这里也可以看到,函数内置了__next__()用法,但是当把生成器中所有值全部生成之后,会抛出一个异常。每个生成器只能使用一次,所以想要再用只能再创建一个。

最近写爬虫用到,所以仔细看了一下特性,yield有个冻结层的功能,第一轮next()取出一个值的同时,函数停留在本行不往下进行,指导一下轮查询的到来,例如:

In [35]: def myFun(number):
    ...:     while True:
    ...:         if number < 15:
    ...:             print("yield开始前")
    ...:             yield number
    ...:             print("yield开始后")
    ...:         number += 1
    ...:         

In [36]: generator = myFun(0)

In [37]: next(generator)
yield开始前
Out[37]: 0

In [38]: next(generator)
yield开始后
yield开始前
Out[38]: 1

In [39]: next(generator)
yield开始后
yield开始前
Out[39]: 2

可以看到,每次的结束log都是在下一轮next下执行的。

还有一点,值传递时用next会传出None,一段代码就全明白了

In [50]: def get_primes(number):
    ...:     while True:
    ...:         if number < 15:
    ...:             print(type(number))
    ...:             number = yield number
    ...:             print(number)
    ...:         number += 1
    ...:         

In [51]: generator = get_primes(2)

In [52]: next(generator)
<class 'int'>
Out[52]: 2

In [53]: next(generator)   # 很显然,因为第一轮的复制,第二轮报错了
None
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-53-323ce5d717bb> in <module>()
----> 1 next(generator) 

<ipython-input-50-922d08ae3a11> in get_primes(number)
      5             number = yield number
      6             print(number)
----> 7         number += 1
      8 

TypeError: unsupported operand type(s) for +=: 'NoneType' and 'int'

工作中send()也很常用,我看到一篇帖子,利用一个简易的生产-消费模型很清楚的表示了send()的用法,是这样的:

import random

def get_data():
    """返回0到9之间的3个随机数"""
    return random.sample(range(10), 3)

def consume():
    """显示每次传入的整数列表的动态平均值"""
    running_sum = 0
    data_items_seen = 0

    while True:
        data = yield
        data_items_seen += len(data)
        running_sum += sum(data)
        print('The running average is {}'.format(running_sum / float(data_items_seen)))

def produce(consumer):
    """产生序列集合,传递给消费函数(consumer)"""
    while True:
        data = get_data()
        print('Produced {}'.format(data))
        consumer.send(data)
        yield

if __name__ == '__main__':
    consumer = consume()
    consumer.send(None)
    producer = produce(consumer)

    for _ in range(10):
        print('Producing...')
        next(producer)

可以看到,代码先对生成器send了一个None,来启动生成器,后面,每次传递生成的data

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值