初步理解Python中的生成器

前言

沒有用過的東西,沒有深入理解的東西很難說本身會,並且被別人一問必然破綻百出。雖然以前有接觸過python協程的概念,可是隻是蜻蜓點水,這兩天的一次交談中,別人問到了協程,頓時語塞,死活想不起來曾經看過的東西,以後忽然想到了yield,但爲時已晚,只能說概念不清,因此本篇先縷縷python的生成器和yield關鍵字。html

什麼是生成器

  • 生成器是一個特殊的程序,能夠被用做控制循環的迭代行爲python

  • 生成器相似於返回值爲數組的一個函數,這個函數能夠接收參數,能夠被調用,可是,不一樣於通常的函數會一次性返回包含了全部數值的數組,生成器一次只產生一個值,這樣消耗的內粗數量大大減小,並且容許調用函數能夠很快的開始處理前幾個返回值。所以,生成器看起來像一個函數可是表現的卻像一個迭代器。數組

python中的生成器

python提供了兩種基本的方式。ide

  • 生成器函數:也是用def來定義,利用關鍵字yield一次返回一個結果,阻塞,從新開始函數

  • 生成器表達式:返回一個對象,這個對象只有在須要的時候才產生結果code

下面詳細講解。協程

生成器函數

爲何叫生成器函數?由於他隨着時間的推移生成了一個數值隊列。通常的函數在執行完畢以後會返回一個值而後退出,可是生成器函數會自動掛起,而後從新拾起繼續執行,他會利用yield關鍵字關起函數,給調用者返回一個值,同時保留了當前的足夠多的狀態,可使函數繼續執行。生成器和迭代協議是密切相關的,可迭代的對象都有一個__next()__成員方法,這個方法要麼返回迭代的下一項,要麼引發異常結束迭代。
爲了支持迭代協議,擁有yield語句的函數被編譯爲生成器,這類函數被調用時返回一個生成器對象,返回的對象支持迭代接口,即成員方法__next()__繼續從中斷處執行執行。
看下面的例子:htm

# codesdef create_counter(n):
    print "create counter"
    while True:        yield n        print 'increment n'
        n += 1cnt = create_counter(2)print cntprint next(cnt)print next(cnt)# output<generator object create_counter at 0x0000000001D141B0>create counter2increment n3

分析一下這個例子:對象


  • 在create_counter函數中出現了關鍵字yield,預示着這個函數每次只產生一個結果值,這個函數返回一個生成器(經過第一行輸出能夠看出來),用來產生連續的n值blog

  • 在創造生成器實例的時候,只須要像普通函數同樣調用就能夠,可是這個調用卻不會執行這個函數,這個能夠經過輸出看出來

  • next()函數將生成器對象做爲本身的參數,在第一次調用的時候,他執行了create_counter()函數到yield語句,返回產生的值2

  • 咱們重複的調用next()函數,每次他都會從上次被掛起的地方開始執行,直到再次遇到了yield關鍵字

爲了更加深入的理解,咱們再舉一個例子。

#codingdef cube(n):
    for i in range(n):        yield i ** 3for i in cube(5):    print i#output0182764

因此從理解函數的角度出發咱們能夠將yield類比爲return,可是功能確實徹底不一樣,在for循環中,會自動遵循迭代規則,每次調用next()函數,因此上面的結果不難理解。

生成器表達式:

生成器表達式來自於迭代和列表解析的組合,關於列表解析的概念和用法能夠參見連接,生成器表達式和列表解析相似,可是他使用尖括號而不是方括號括起來的。以下代碼:

>>> # 列表解析生成列表>>> [ x ** 3 for x in range(5)]
[0, 1, 8, 27, 64]>>> >>> # 生成器表達式>>> (x ** 3 for x in range(5))<generator object <genexpr> at 0x000000000315F678>>>> # 二者之間轉換>>> list(x ** 3 for x in range(5))
[0, 1, 8, 27, 64]

就操做而言,生成器表若是使用大量的next()函數會顯得十分不方便,for循環會自動出發next函數,因此能夠按下面方式使用:

>>> for n in (x ** 3 for x in range(5)):    print('%s, %s' % (n, n * n))    
0, 01, 18, 6427, 72964, 4096>>>

二者比較

一個迭代既能夠被寫成生成器函數,也能夠被協程生成器表達式,均支持自動和手動迭代。並且這些生成器只支持一個active迭代,也就是說生成器的迭代器就是生成器自己。

總結

想起了初中時候老師常常說的,眼觀千遍,不如手動一遍。

不向靜中參妙理,縱然穎悟也虛浮 立乎其大  和而不一樣 古之成大事者,不唯有超世之才,亦必有堅韌不拔之志

原文地址:https://www.cnblogs.com/cotyb/p/5260032.html

相關文章
相關標籤/搜索