前言
沒有用過的東西,沒有深刻理解的東西很難說自己會,而且被別人一問必然破綻百出。雖然之前有接觸過python協(xié)程的概念,但是只是走馬觀花,這兩天的一次交談中,別人問到了協(xié)程,頓時語塞,死活想不起來曾經(jīng)看過的東西,之后突然想到了yield,但為時已晚,只能說概念不清,所以本篇先縷縷python的生成器和yield關(guān)鍵字。
什么是生成器
1、生成器是一個特殊的程序,可以被用作控制循環(huán)的迭代行為
2、生成器類似于返回值為數(shù)組的一個函數(shù),這個函數(shù)可以接收參數(shù),可以被調(diào)用,但是,不同于一般的函數(shù)會一次性返回包含了所有數(shù)值的數(shù)組,生成器一次只產(chǎn)生一個值,這樣消耗的內(nèi)粗數(shù)量大大減少,而且允許調(diào)用函數(shù)可以很快的開始處理前幾個返回值。因此,生成器看起來像一個函數(shù)但是表現(xiàn)的卻像一個迭代器。
python中的生成器
python提供了兩種基本的方式。
1)、生成器函數(shù):也是用def來定義,利用關(guān)鍵字yield一次返回一個結(jié)果,阻塞,重新開始
2)、生成器表達式:返回一個對象,這個對象只有在需要的時候才產(chǎn)生結(jié)果
下面詳細講解。
1、生成器函數(shù)
為什么叫生成器函數(shù)?因為他隨著時間的推移生成了一個數(shù)值隊列。一般的函數(shù)在執(zhí)行完畢之后會返回一個值然后退出,但是生成器函數(shù)會自動掛起,然后重新拾起繼續(xù)執(zhí)行,他會利用yield關(guān)鍵字關(guān)起函數(shù),給調(diào)用者返回一個值,同時保留了當(dāng)前的足夠多的狀態(tài),可以使函數(shù)繼續(xù)執(zhí)行。生成器和迭代協(xié)議是密切相關(guān)的,可迭代的對象都有一個__next()__成員方法,這個方法要么返回迭代的下一項,要么引起異常結(jié)束迭代。
為了支持迭代協(xié)議,擁有yield語句的函數(shù)被編譯為生成器,這類函數(shù)被調(diào)用時返回一個生成器對象,返回的對象支持迭代接口,即成員方法__next()__繼續(xù)從中斷處執(zhí)行執(zhí)行。
看下面的例子:
# 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
分析一下這個例子:
為了更加深刻的理解,我們再舉一個例子。
#codingdef cube(n): for i in range(n): yield i ** 3for i in cube(5): print i#output0182764
所以從理解函數(shù)的角度出發(fā)我們可以將yield類比為return,但是功能確實完全不同,在for循環(huán)中,會自動遵循迭代規(guī)則,每次調(diào)用next()函數(shù),所以上面的結(jié)果不難理解。
2、生成器表達式
生成器表達式來自于迭代和列表解析的組合,關(guān)于列表解析的概念和用法可以參見我之前的博客,生成器表達式和列表解析類似,但是他使用尖括號而不是方括號括起來的。如下代碼:
>>> # 列表解析生成列表>>> [ x ** 3 for x in range(5)][0, 1, 8, 27, 64]>>> >>> # 生成器表達式>>> (x ** 3 for x in range(5))<generator object <genexpr> at 0x000000000315F678>>>> # 兩者之間轉(zhuǎn)換>>> list(x ** 3 for x in range(5))[0, 1, 8, 27, 64]
就操作而言,生成器表如果使用大量的next()函數(shù)會顯得十分不方便,for循環(huán)會自動出發(fā)next函數(shù),所以可以按下面方式使用:
>>> for n in (x ** 3 for x in range(5)): print('%s, %s' % (n, n * n)) 0, 01, 18, 6427, 72964, 4096>>> 兩者比較
一個迭代既可以被寫成生成器函數(shù),也可以被協(xié)程生成器表達式,均支持自動和手動迭代。而且這些生成器只支持一個active迭代,也就是說生成器的迭代器就是生成器本身。
總結(jié)
想起了初中時候老師經(jīng)常說的,眼觀千遍,不如手動一遍。
新聞熱點
疑難解答
圖片精選