面试被问到python3 的asyncio模块、python2中的yield和yield from的区别
面的第一家觉得回答的不是很好, 回来进行收集整理一番,以便巩固记忆
Python中的协程大概经历了三个阶段:
最初的生成器变形yield/send
引入@asyncio.coroutine和yield from
在最近的python3.5版本中引入async/await字段
下面将对上边的三个阶段进行说明
1、 生成器变形yield/send
普通函数中如果出现了yield, name该函数就不是普通的函数, 而是一个生成器
1 def gen():2 for i in range(1,10):3 yieldi4
5 g =gen()6 for i ing:7 print(i)
像上面的代码 g 就是一个生成器, 生成器就是一种迭代器,可以使用for进行迭代,生成器最大的特点就是可以接受一个外部传入的变量,根据变脸内容计算返回结果
1 def gen():2 whileTrue:3 i = 0
4 x = yieldi5 if x == 0:6 break
7 i = i*x8 g =gen()9 print(g.send(None))10 print(g.send(1))11 print(g.send(2))12 print(g.send(0))
上面的步骤中,x = yield i最重要也最容易理解错,下面详细接介绍该语句的运行流程
其实x = yield i包含了三个步骤:
向函数外抛出(返回)i
暂停,等待next()和send()恢复
赋值receive=MockGetValue() 。 这个MockGetValue()是假想函数,用来接收send()发送进来的值
执行流程:
通过g.send(None)或者next(g)启动生成器函数, 并执行到第一个yield语句停止,注意在这里相当于执行了上边的1,2步,程序返回yield后边的i值后暂停,并没有执行第三步, 注意第一次这里send(None)函数的参数必须传None否者会报错
通过g.send(1), 会传入值,从上一次暂停的位置继续执行,从第三步执行赋值操作后 再执行1,2步。
当我们传g.send(0)时候, 会主动break 并且退出循环,最后整个函数执行完毕,所以会得到StopIteration异常。
2、yield from
1 def g1():2 yield range(5)3 def g2():4 yield from range(5)5
6 it1 =g1()7 it2 =g2()8 for x init1:9 print(x)10
11 for x init2:12 print(x)13
14 """15 会输出16 range(0, 5)17 0
18 1
19 2
20 3
21 4
22 """
个人理解yield仅仅是截断并返回,而yield from相当于解析了后边的可迭代对象,并返回每一个item。
yield from iterable本质上等于for item in iterable: yield item的缩写版
注意:yield_from 后边的必须为可迭代对象(iterable)
3、 asyncio.cotoutine和yield from
yield from在asyncio模块中得以发扬光大。之前都是我们手工切换协程,现在当声明函数为协程后,我们通过事件循环来调度协程。
示例代码
1 importasyncio,random2 @asyncio.coroutine3 defsmart_fib(n):4 index =05 a =06 b = 1
7 while index