Python入门篇-生成器函数
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.生成器概述
1>.生成器generator
生成器指的是生成器对象,可以由生成器表达式得到,也可以使用yield关键字得到一个生成器函数,调用这个函数得到一个生成器对象
2>. 生成器函数
函数体中包含yield语句的函数,返回生成器对象
生成器对象,是一个可迭代对象,是一个迭代器
生成器对象,是延迟计算,惰性求值的
包含yield语句的生成器函数生成生成器对象的时候,生成器函数的函数体不会立即执行
next(generator)会从函数的当前位置向后执行到之后碰到的第一个yield语句,会弹出值,并暂停函数执行
再次调用next函数,和上一条一样的处理过程
没有多余的yield语句能被执行,继续调用next函数,会抛出StopIteration异常
3>.编写一个生成器函数样例
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:y1053419035@qq.com 6 7 """ 8 关于生成器函数的相关说明: 9 10 在生成器函数中,使用多个yield语句,执行一次后会暂停执行,把yield表达式的值返回 11 12 再次执行会执行到下一个yield语句 13 14 return 语句依然可以终止函数运行,但return语句返回值不能被捕获到 15 16 return 会导致无法继续获取下一个值,抛出StopIteration异常 17 18 如果函数没有显示的return语句,如果生成器函数执行到结尾,一样会抛出StopIteration异常哟 19 20 """ 21 def gen(): 22 print('line 1') 23 yield 1 24 print('line 2') 25 yield 2 26 print('line 3') 27 return 3 28 29 next(gen()) 30 31 next(gen()) 32 33 g = gen() 34 35 print(next(g)) 36 print(next(g)) 37 38 # print(next(g)) #报错:StopIteration: 3,因为已经没有多余的yield语句啦,上面已经被调用两次了 39 40 print(next(g, 'End')) #如果没有元素就给个缺省值 41 42 43 44 #以上代码执行结果如下: 45 line 1 46 line 1 47 line 1 48 1 49 line 2 50 2 51 line 3 52 End
二.生成器应用
1>.无限循环
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:y1053419035@qq.com 6 7 8 def counter(): 9 i = 0 10 while True: 11 i += 1 12 yield i 13 14 def inc(c): 15 return next(c) 16 17 c = counter() #这是一个生成器对象 18 19 print(inc(c)) 20 print(inc(c)) 21 22 23 24 #以上代码输出结果如下: 25 1 26 2
2>.计数器
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:y1053419035@qq.com 6 7 def inc(): 8 def counter(): 9 i = 0 10 while True: 11 i += 1 12 yield i 13 c = counter() 14 return lambda : next(c) #这里返回的是匿名函数 15 16 foo = inc() 17 print(foo()) 18 print(foo()) 19 20 21 22 #以上代码输出结果如下: 23 1 24 2
3>.处理递归问题
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:y1053419035@qq.com 6 7 8 def fib(): 9 x = 0 10 y = 1 11 while True: 12 yield y 13 x, y = y, x+y 14 15 foo = fib() 16 17 for _ in range(5): 18 print(next(foo)) 19 20 for _ in range(100): 21 next(foo) 22 23 print(next(foo)) 24 25 26 #以上代码输出结果如下: 27 1 28 1 29 2 30 3 31 5 32 6356306993006846248183
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com pre = 0 cur = 1 print(pre,cur,end=" ") def fib(n,pre=0,cur=1): pre,cur = cur,pre + cur print(cur,end=" ") if n == 2: return fib(n-1,pre,cur) fib(106)
4>.协程(coroutine)
(1)生成器的高级用法 (2)比进程,线程轻量级 (3)是在用户空间调度的一种实现 (4)Python3 asyncio就是协程实现,已经加入到标准库 (5)Python3.5 使用async,await关键字直接原生支持协程 协程调度器实现思路: 有2个生成器A,B next(A)后,A执行到了yield语句暂停,然后去执行next(B),B执行到yield语句也暂停,然后再次调用next(A),再调用next(B),周而复始,就实现了调度的效果 可以引入调度的策略来实现切换的方式 (6)协程就是一种非抢占式调度
三.yield from
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:y1053419035@qq.com 6 7 8 def inc(): 9 for x in range(1000): 10 yield x 11 12 foo = inc() 13 print(next(foo)) 14 print(next(foo)) 15 print(next(foo)) 16 17 print("*" * 20 + "我是分割符" +"*" * 20) 18 19 """ 20 以上代码可以使用yield from代码改写,等价于下的代码: 21 """ 22 def inc(): 23 yield from range(1000) 24 25 bar = inc() 26 print(next(bar)) 27 print(next(bar)) 28 print(next(bar)) 29 30 31 32 #以上代码输出结果如下: 33 0 34 1 35 2 36 ********************我是分割符******************** 37 0 38 1 39 2
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com """ yield from是Python 3.3出现新的语法 yield from iterable 是 for item in iterable: yield item 形式的语法糖 """ #从可迭代对象中一个个拿元素 def counter(n): for x in range(n): yield x def inc(n): yield from counter(n) foo = inc(10) print(next(foo)) print(next(foo)) #以上代码执行结果如下: 0 1