Python Generator函数和协程
学习Generator函数之前要了解一些定义
迭代器(Iterator)
对象定义了__next__
方法就是迭代器。
可迭代对象(Iterable)
对象可以定义__iter__
用来返回迭代器的方法,或者定义__getitem__
通过下标获取元素的方法,含有这两种方法的对象就是可迭代的。
生成器(Generator)
返回值用yield
返回的函数,生成器是创建迭代器的最简单方式,自动实现__iter__
和__next__
方法
def generatorFunc():
for i in range(0, 10):
yield i #这句需要注意,生成器函数专用
for v in generatorFunc():
print(v)
'''
结果:
0
1
2
3
4
5
6
7
8
9
'''
yield 类似普通函数的return,每次执行到yield则返回一次其后的值然后暂停执行,并不是一次生成所有值后返回,而是在执行next时继续执行到下一次的yield。这样做的好处是返回的是非常多的数据时并不是一次全部生成,而是按次序生成,这样可以节省很多空间。
for a in fibo(10):
def fibo(n):
x1=x2=1
for i in range(n):
yield x1
x1,x2 = x2, x1+x2
gen = fibo(3) #获取迭代器对象
print(next(gen)) #使用next获取写一个yield后的值
print(next(gen))
print(next(gen))
print(next(gen))#报错StopIteration,使用next方法如果没有yield再生成值返回则会报错, next是迭代器返回值使用的函数
'''
结果:
1
1
2
Traceback (most recent call last):
File "fibo.py", line 12, in <module>
print(next(gen))
StopIteration
'''
注意可迭代和迭代器的区别,如:string是可以通过下标访问的,所以string是iterable 但是他却不是迭代器
但是可迭代对象是可以通过内建函数iter
转换成迭代器
>>> a = '1234'
>>> next(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object is not an iterator
>>> i = iter(a) #通过iter把可迭代对象转换成迭代器
>>> next(i)
'1'
Python3中很多函数再返回多个值时返回的是迭代器,如map 、filter等
协程
协程又叫做微线程,和线程不一样,协程是在一个线程执行,但是比线程运行效率高,它不需要线程切换的开销,也不需要锁机制来控制同步互斥,它与函数调用很相似,但是和函数调用又很大区别,并不是使用函数栈来控制。
协程需要使用生成器方式来实现,之前我们使用生成器来生产数据,携程用法相反,我们生产数据,发送给协程来消费。
先看例子:
def grep(p):
print(p)
x = 0;
while True:
x+=1
line = (yield x)
print(line)
g = grep('grep') #返回一个生成器对象
r = next(g) #启动生成器 或者使用g.send(None)来启动
print(r) #返回yield之后的x 并使携程暂停在yield位置
r = g.send('aaa') #通过使用send向协程传递‘aaa’使yield语句返回‘aaa’,并返回yield后的值
print(r)
g.close()#关闭携程
'''
结果:
grep
1
aaa
2
'''
- 首先我们需要调用next或者send(None)来启动生成器。
- 我们发送数据到协程使用x = send(value)把value发送到协程,然后接受yield的数据,协程接着运行到yield,然后我们再用send发送数据和接收值…
- 关闭协程使用close函数关闭