生成器与迭代器的使用规则
斐波拉契数列
1 def fib(max): 2 n,a,b = 0,0,1 3 while n < max: 4 print(b) 5 a,b = b,a+b 6 n = n + 1 7 return 'done' 8 9 10 fib(10) 11 #注意赋值语句:a,b = b,a+b 12 13 14 a,b = b,a+b 15 1,1 = 1,0+1 16 1 ,2 = 1,1+1 17 2,3 = 2,1+2 18 3,5 = 3,2+3 19 5,8 = 5,3+5 20 8,13 = 8,5+8 21 13,21= 13,8+13
用函数变成生成器修改斐波拉契数列
1 #将print改为yeild: 2 def fib(max): 3 n,a,b = 0,0,1 4 while n < max: 5 #print(b) 6 yield b 7 a,b = b,a+b 8 n = n + 1 9 return 'done' 10 11 ret = fib(10) 12 print(ret) 13 14 15 #显示结果: 16 <generator object fib at 0x0000000000B387D8>
生成器的调用
每执行一个ret.__next__(),就调用一次。
一、优点:
每一次调用就会中断退出,然后在调用在退出,以此类推。
例如:每调用一次,程序就会退出,然后在去做别的事儿,做完在用ret.__next__(),调用下一个生成器。
1 def fib(max): 2 n,a,b = 0,0,1 3 while n < max: 4 #print(b) 5 yield b 6 a,b = b,a+b 7 n = n + 1 8 return 'done' 9 10 ret = fib(10) 11 print(ret) 12 print(ret.__next__()) 13 print(ret.__next__()) 14 print(ret.__next__())
二、缺点:
__next__()调用超出迭代器的范围,所以报错。
生产中是不知道迭代器的元素有多少,所以只能等待异常的出现。
因此可以用异常处理来抓住生成器的结束,如下:
1 def fib(max): 1 6 2 n,a,b = 0,0,1 7 3 while n < max: 8 16 4 #print(b) 5 yield b 9 13 17 #中断退出,并将至返回给next() 6 a,b = b,a+b 14 7 n = n + 1 15 8 return '异常' 9 10 g = fib(6) 2 11 12 while True: 3 11 13 try: 4 14 #内置方法,与__next__()是一样的,返回到上一次yield中断的地方 15 x = next(g) 5 12 16 print('g:',x) 10 18 17 except StopIteration as e: 18 print('Generator return values:',e.value) 19 break
协程
一、概念:cpu调用程序分为:进程--(包含多个)-->线程--(包含多个)-->协程
二、作用:通过生成器yield实现单线程的情况下实现并发运算效果(异步IO的雏形)。
三、工作原理:
1、生成器只有在调用时才会生成相应的数据 2、调用方式有 " str__next__.() str.send() ", 3、并且每调用一次就产生一个值调用到最后一个值后会报错 4、报错可用try和except做异常处理
四、注意事项:
next:是直接调用yield,并不会传值。
send:是调用并直接传值给yield。
五、实例:
1 #!/usr/bin/env python 2 # -*- coding:utf8 -*- 3 # Author:Dong Ye 4 5 6 ''' 7 定义两个模型: 8 一个是生产包子的。(生成器) 9 另一个是吃包子的。(迭代器) 10 11 这段功能实现了异步IO的雏形,也是一个简单的协程处理方式。 12 协程的特点:实际是串行方式分开执行的,但由于运行效果快,给人的感觉像是并行。 13 因此,协程也叫作:单线程下的并行执行效果。 14 协程是包含在线程里的一个单位,线程时进程的一个单位。 15 例如:enginx在异步单线程下,比多线程要快好多倍,也就是这种效果。 16 ''' 17 18 import time 19 20 21 #吃包子的 22 def consumer(name): 23 print('%s 准备吃包子了!' % name) 24 while True: 25 baozi = yield 26 print("包子[%s]来了。被[%s]吃了!" %(baozi,name)) 27 28 29 #生产包子的 30 def producer(name): 31 #先定义2个协程(消费者)#将函数变成生成器 32 c1 = consumer('A') #2个消费者 33 c2 = consumer('B') #相当于2个协程(进程,线程,协程) 34 #开始调用生成器初始化(准备吃包子) 35 c1.__next__() #开始调用生成器,只有next的时候才会到yield进行下一个操作 36 c2.__next__() 37 print('老子开始吃包子拉!') 38 #循环的次数,每次循环都会传值给生成器(产生什么样的包子) 39 for i in range(10): 40 time.sleep(1) 41 print("做了一个包子,分2半,一人一半") 42 c1.send(i) #包子的类型 43 c2.send(i) 44 45 46 producer("alex") 47 48 49 50 ''' 51 #手动做包子: 52 c = consumer("dy") 53 c.__next__() 54 #c.__next__() 55 56 b1 = "韭菜馅" 57 c.send(b1) #调用+传值 58 #c.__next__() #只调用,不传值 59 ''' 60 61 62 63 显示结果: 64 A 准备吃包子了! 65 B 准备吃包子了! 66 老子开始吃包子拉! 67 做了一个包子,分2半,一人一半 #任务1 68 包子[0]来了。被[A]吃了! #任务2 69 包子[0]来了。被[B]吃了! #任务3 70 做了一个包子,分2半,一人一半 71 包子[1]来了。被[A]吃了! 72 包子[1]来了。被[B]吃了! 73 做了一个包子,分2半,一人一半 74 包子[2]来了。被[A]吃了! 75 包子[2]来了。被[B]吃了! 76 做了一个包子,分2半,一人一半 77 包子[3]来了。被[A]吃了! 78 包子[3]来了。被[B]吃了! 79 做了一个包子,分2半,一人一半 80 包子[4]来了。被[A]吃了! 81 包子[4]来了。被[B]吃了! 82 做了一个包子,分2半,一人一半 83 包子[5]来了。被[A]吃了! 84 包子[5]来了。被[B]吃了! 85 做了一个包子,分2半,一人一半 86 包子[6]来了。被[A]吃了! 87 包子[6]来了。被[B]吃了! 88 做了一个包子,分2半,一人一半 89 包子[7]来了。被[A]吃了! 90 包子[7]来了。被[B]吃了! 91 做了一个包子,分2半,一人一半 92 包子[8]来了。被[A]吃了! 93 包子[8]来了。被[B]吃了! 94 做了一个包子,分2半,一人一半 95 包子[9]来了。被[A]吃了! 96 包子[9]来了。被[B]吃了!