生成器

生成器generator

  • 生成器指的是生成器对象,可以由生成器表达式得到,也可以使用yield关键字得到一个生成器函数,调用这个函数得到一个生成器对象

生成器函数

  • 函数体中包含yield语句的函数,返回生成器对象
  • 生成器对象,是一个可迭代对象,是一个迭代器
  • 生成器对象,是延迟计算、惰性求值的

示例:

  1. In [2]: def inc():
  2. ...: for i in range(5):
  3. ...: yield i
  4. ...:
  5. ...: print(type(inc))
  6. ...: print(type(inc()))
  7. ...: x = inc()
  8. ...: print(type(x))
  9. ...: print(next(x))
  10. ...:
  11. ...: for m in x:
  12. ...: print(m, '*')
  13. ...:
  14. <class 'function'>
  15. <class 'generator'>
  16. <class 'generator'>
  17. 0
  18. 1 *
  19. 2 *
  20. 3 *
  21. 4 *
  • yeild语句返回的结果不在是一个值,而是一个generator对象
  • 生成器函数需要通过next()的方式来获取值
  • 也可以使用for循环获取,生成器对象迭代走完一遍后不可再次迭代

生成器总结

  • 生成器函数的函数体不会立即执行,必须调用后生成一个生成器
  • 在生成器函数中,可以使用多个yield语句,使用next(generator)执行一次会暂停执行,把yeild值返回
  • 再次执行会执行到下一次yield语句
  • return语句依然可以终止函数运行,但return语句的返回值不能被获取的到
  • return会导致无法继续获取下一个值,跑出StopIteration异常
  • 如果函数没有显示的return语句,如果生成器函数执行到结尾,一样会跑出StopIteration异常
  • 如不想出现异常,可使用传入默认值的方式,如:next(g, ‘’End”)

协程coroutine

  • 生成的高级用法
  • 比进程、协程轻量级
  • 是在用户空间调度函数的一种实现
  • Python3 asyncio就是协程实现,已经加入到了标准库
  • python 3.5使用async、 await关键字直接原生支持协程
  • 协程调度的实现思路

    • 有2个生成器A和B
    • next(A)后,A执行到了yield语句暂停,然后去执行next(B),B执行到yield语句也暂停,然后再次调用next(A),再调用next(B),周而复始,就实现了调度的效果。
    • 可以引入调度的策略来实现切换的方式
  • 协程是一种非抢占式调度。

yeild from

  • 简化yeild代码的语法糖
  • 示例
def inc():
    for x in range(1000):
        yeild x
# 上述代码等同于:      
def inc():
    yeild from range(1000)