1、生成器介绍
首先请确信,生成器就是一种迭代器。生成器拥有next方法并且行为与迭代器完全相同,这意味着生成器也可以用于Python的for循环中。
2、生成器函数
1)、自定义生成器
1 def generator1(): 2 yield 1 3 yield 2 4 yield 3 5 6 7 g = generator1() 8 print(next(g)) 9 print(next(g)) 10 print(next(g))
#执行结果 1 2 3
我们需要注意的是:第一次调用生成器的next方法时,生成器才开始执行生成器函数(而不是构建生成器时),直到遇到yield时暂停执行(挂起),并且yield的参数将作为此次next方法的返回值;
1 >>> def gen(): 2 ... yield 1 3 ... yield 2 4 ... 5 >>> g = gen() 6 >>> type(g) 7 <class 'generator'>
当调用next方法时生成器函数结束,再次调用next方法将抛出StopIteration异常。(即for循环的终止条件)
1 >>> next(g) 2 1 3 >>> next(g) 4 2 5 >>> next(g) 6 Traceback (most recent call last): 7 File "<stdin>", line 1, in <module> 8 StopIteration
其他补充知识:
1、生成器带参数
1 >>> def counter(start=0): 2 ... while True: 3 ... yield start 4 ... start +=1 5 ... 6 >>> count = counter() 7 >>> next(count) 8 0 9 >>> next(count) 10 1 11 >>> next(count) 12 2 13 >>> next(count) 14 3
协同程序(coroutine)
1、可以方便地挂起、恢复,并且有多个入口点和出口点;
2、多个协同程序间表现为协作运行,如A的运行过程中需要B的结果才能继续执行。
协程的特点决定了同一时刻只能有一个协同程序正在运行。得益于此,协程间可以直接传递对象而不需要考虑资源锁、或是直接唤醒其他协程而不需要主动休眠,就像是内置了锁的线程。在符合协程特点的应用场景,使用协程无疑比使用线程要更方便。
协程函数的例子:
文件a.txt,打印出所有含有“apple”的行
apple 10 3 iphone 4000 1 macbook 3000 2 chicken 10 3 apple 11 22 apple 20 23
1 def cat(file_path):#定义cat函数寻找文件读取内容 2 with open(file_path) as f: 3 for line in f: 4 if not line: 5 continue 6 else: 7 yield line 8 9 def grep(source, keywords):#判断函数,是否含有相应的关键字 10 if keywords in source: 11 yield source
#执行代码
1 source1 = cat("a.txt") #生成器 2 print(source1) 3 for i in source1: 4 g1 = grep(i,"apple") 5 6 for i in g1: 7 print(i, end="")
#执行结果
<generator object cat at 0x1011030f8> apple 10 3 apple 11 22 apple 20 23
生成器中的send(value)方法。send是除next外另一个恢复生成器的方法。此时yield语句变成了yield表达式,这意味着yield现在可以有一个值,而这个值就是在生成器的send方法被调用从而恢复执行时,调用send方法的参数
1 from urllib.request import urlopen 2 3 def get(): 4 while True: 5 url = yield 6 res = urlopen(url).read() 7 print(res)
1 g = get() 2 next(g) 3 g.send("http://www.sina.com.cn")
注意:
1、调用send传入非None值前,生成器必须处于挂起状态,否则将抛出异常。未启动的生成器仍可以使用None作为参数调用send。
2、如果使用next恢复生成器,yield表达式的值将是None。