1. 程式人生 > >生成器與叠代器的使用規則

生成器與叠代器的使用規則

post bre 並發 isp print nbsp 修改 包子 產生

斐波拉契數列

技術分享圖片
 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]吃了!
異步IO的雛形

生成器與叠代器的使用規則