課時49:魔法方法:生成器
目錄:
一、生成器
二、課時49課後習題及答案
*********************
一、生成器
**********************
生成器的學習並不涉及魔法方法,甚至它巧妙地避開了類和對象,僅通過普通地函數就可以實現了。
生成器其實是叠代器的一種實現。
- 生成器的發明一方面是為了使得Python更為簡潔,因為,叠代器需要我們自己去定義一個類和實現相關的方法,而生成器則只需要在普通的函數中加上一個yield語句即可。
- 另一方面,生成器的發明,使得Python模仿協同程序的概念得以實現。所謂協同程序,就是可以運行得獨立函數調用,函數可以暫停或者掛起,並在需要得時候從程序離開得地方繼續或者重新開始。
對於調用一個普通的Python函數,一般是從函數的第一行代碼開始執行,結束於return語句、異常、或者函數所有語句執行完畢。一旦函數將控制權交還給調用者,就意味著全部結束。函數中做的所有工作以及保存在局部變量中的數據都將丟失。再次調用這個函數時,一切將從頭創建。
Python是通過生成器來實現類似於協同程序的概念:生成器可以暫時掛起函數,並保留函數的局部變量等數據,然後在再次調用它的時候,從上次暫停的位置繼續執行下去。
舉個例子:
>>> def myGen(): print("生成器被執行!") yield 1 yield 2 >>> myG = myGen()>>> next(myG) 生成器被執行! 1 >>> next(myG) 2 >>> next(myG) Traceback (most recent call last): File "<pyshell#9>", line 1, in <module> next(myG) StopIteration
正如大家所見,當函數結束的時候,一個StopIteration異常就會拋出。由於Python的for循環會自動調用next()方法和處理StopIteration異常,所以for循環當然也是可以對生成器產生作用的:
>>> for i in myGen(): print(i) 生成器被執行! 1 2
像前面介紹的斐波那契的例子,也可以用生成器來實現:
>>> def fibs(): a = 0 b = 1 while True: a,b = b,a + b yield a >>> for each in fibs(): if each > 100: break print(each) 1 1 2 3 5 8 13 21 34 55 89
事到如今,你應該已經很好的掌握了列表推到式子(並沒有,哭唧唧),那下邊這個列表推導式表達的是啥意思:
>>> a = [i for i in range(100) if not(i%2) and i%3]
其實上邊這個列表推導式求得就是100以內,能被2整除但不能被3整除的所有整數:
>>> a
[2, 4, 8, 10, 14, 16, 20, 22, 26, 28, 32, 34, 38, 40, 44, 46, 50, 52, 56, 58, 62, 64, 68, 70, 74, 76, 80, 82, 86, 88, 92, 94, 98]
python3除了有列表推導式,還有字典推導式:
>>> b = {i:i%2 == 0 for i in range(10)} >>> b {0: True, 1: False, 2: True, 3: False, 4: True, 5: False, 6: True, 7: False, 8: True, 9: False}
還有集合推導式:
>>> c = {i for i in [1,1,2,3,3,4,5,5,5,6,7,7,8]} >>> c {1, 2, 3, 4, 5, 6, 7, 8}
那是否有字符串推導式和元組推導式呢?試一試:
>>> d = "I love zww" >>> d ‘I love zww‘
噢,不行,因為在雙引號內,所有的東西都變成了字符串,所以不存在字符串推導式,那元組推導式呢?
>>> e = (i for i in range(10)) >>> e <generator object <genexpr> at 0x000002001EC4CB88>
咦?似乎這個不是什麽推導式嘛。generator,多麽熟悉的單詞,就是生成器嘛!沒錯用普通小括號括起來的正是生成器推導式,來證明一下:
>>> next(e) 0 >>> next(e) 1 >>> next(e) 2 >>> next(e) 3 >>> next(e) 4
用for語句把剩下的給打印出來:
>>> for each in e: print(each) 5 6 7 8 9
還有一個特性更牛,生成器推導式如果作為函數的參數,可以直接寫推導式,而不用加小括號:
>>> sum(i for i in range(100) if i % 2) 2500
【擴展閱讀】提高你的 Python:解釋 yield 和 Generators(生成器)
*******************************
二、課時49課後習題及答案
*******************************
預知後文如何?請君耐心等待.
課時49:魔法方法:生成器