1. 程式人生 > >課時49:魔法方法:生成器

課時49:魔法方法:生成器

extra target blank filter 一行 info 技術分享 python函數 type

目錄:

  一、生成器

  二、課時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:魔法方法:生成器