Neutron中的yield关键词进行协程的编程场景并不是很多,但是了解yield,对了解协程的基本概念和原理会有很大的帮助。Python中的yield与迭代器的概念相关,我们先从迭代器的概念说起:
一 迭代器
迭代器(iterator),严格地说是一个容器对象,根据迭代器协议(规则),它需要实现两个基本方法:
1 __iter__,返回迭代器自身(容器对象);
2 next,返回迭代器下一个元素(从Python 3开始,改为__next__)。
首先看一个例子:
class myiter(object):
def __init__(self,count):
self.count=count
def __iter__(self):
return self
def __next__(self):
if(0>=self.count):
raise StopIteration()
else:
self.count -= 1
return self.count
for e in myiter(4):
print(e)
迭代器的用法很精练,不过这种精练不够直接
这段代码的输出结果是:
3
2
1
0
需要解释的是“for e in myiter(4)”,这一句话有三层含义:
1 myiter(4),构建一个myiter对象,传入参数值是4;
2 通过__iter__函数,返回一个迭代器;
3 通过__next__函数,一个元素一个元素顺序获取,直到元素获取结束(raise StopIteration())。
我们可以把for e in myiter(4)这句代码改写一下,看起来会更直接:
#构建一个myiter(4)对象it
myiter it = myiter(4)
#循环调用it的__next__函数
while 1:
e=it.__next__()
print(e)
通过上述代码,我们看到,一个class只要实现__iter__、__next__,这两个函数,就可以称为迭代器。
二 yield关键词
使用yeild关键进行编程,就涉及了迭代器的概念。先看下面这个例子:
def fy(count):
c=count
while c>0:
c=c-1
yield c
f=fy(4)
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())
上面的这个例子,让人感觉莫名其妙:fy表面上看起来是一个函数,f不过是一个函数对象而已,怎么会突然冒出一个成员函数__next__出来?
这一切都是因为fy中的一句yield c,原本仅仅是一个函数fy,由于yield的存在,变得完全不同。yield在这里起到的作用就是把一个普通的函数变成了一个生成器。所谓生成器,简单理解就是:迭代器+协程。也就是说yield有两重作用。
yield的第一重作用是把一个普通函数变成了一个迭代器。既然是迭代器,就得具有__next__函数,所以yield会给这个生成器加一个__next__函数,而这个__next__函数的具体实现,就相对于原来的函数体。我们先把fy函数变成一个迭代器,伪代码如下:
class fy_generator(object):
def __init__(self,count):
self.count=count
def __iter__(self):
return self
def __next__(self):
c=self.count
while c>0:
c=c-1
yield c
这个迭代器的__next__函数中,仍然具有yield这个关键词,因为它已经把一个普通函数变成了一个迭代器,所以此时的yield将只会具有第二层作用,把__next__函数变成一个协程。yield的第二层作用,具体描述如下:
1 当__next__函数被调用,执行到yield时,首先相对于return c。
2 但是yield c又不是完全等价于return c,否则函数就退出了。所以,yield的第2个功能相对于保存了当时运行的上下文,把函数挂起。
3 既然把函数挂起,就相对于该协程让出程序执行权(让出上下文,由另外的协程来运行)。
4 当这个__next__函数再次被调用,它是从当初挂起的地方继续执行,直到再次执行yield c那句函数,然后又开始从第1点开始循环。
5 __next__函数可能这样一直循环下去,也可能在某种情况下没有执行到yield c,就函数退出了,那么此时__next__函数会抛出一个异常:raise StopIteration。
综上,关于yield两重作用的描述,重新解释一下所举的例子,如下表:
Neutron使用yield关键词编程,实际上还是属于用户(编程者/应用程序)自己对协程进行调度(函数挂起,让渡给别的函数执行)。