前言
Python生成器(generator)并不是一個(gè)晦澀難懂的概念。相比于MetaClass和Closure等概念,其較為容易理解和掌握。但相對(duì)于程序結(jié)構(gòu):順序、循環(huán)和分支而言其又不是特別的直觀。無(wú)論學(xué)習(xí)任何的東西,概念都是非常重要的。正確樹立并掌握一些基礎(chǔ)的概念是靈活和合理運(yùn)用的前提,本文將以一種通俗易懂的方式介紹一下generator和yield表達(dá)式。
1. Iterator與Iterable
首先明白兩點(diǎn):
Iterator(迭代器)是可迭代對(duì)象; 可迭代對(duì)象并不一定是Iterator;比較常見的數(shù)據(jù)類型list、tuple、dict等都是可迭代的,屬于collections.Iterable類型;
迭代器不僅可迭代還可以被內(nèi)置函數(shù)next調(diào)用,屬于collections.Iterator類型;
迭代器是特殊的可迭代對(duì)象,是可迭代對(duì)象的一個(gè)子集。
將要介紹的gererator(生成器)是types.GeneratorType類型,也是collections.Iterator類型。
也就是說生成器是迭代器,可被next調(diào)用,也可迭代。
三者的包含關(guān)系:(可迭代(迭代器(生成器)))
迭代器:可用next()函數(shù)訪問的對(duì)象; 生成器:生成器表達(dá)式和生成器函數(shù);2. Python生成器
python有兩種類型的生成器:生成器表達(dá)式和生成器函數(shù)。
由于生成器可迭代并且是iterator,因此可以通過for和next進(jìn)行遍歷。
2.1 生成器表達(dá)式
把列表生成式的[]改成()便得到生成器表達(dá)式。
>>> gen = (i + i for i in xrange(10))>>> gen<generator object <genexpr> at 0x0000000003A2DAB0>>>> type(gen)<type 'generator'>>>> isinstance(gen, types.GeneratorType) and isinstance(gen, collections.Iterator) and isinstance(gen, collections.Iterable)True>>>
2.2 生成器函數(shù)
python函數(shù)定義中有關(guān)鍵字yield,該函數(shù)便是一個(gè)生成器函數(shù),函數(shù)調(diào)用返回的是一個(gè)generator.
def yield_func(): for i in xrange(3): yield igen_func = yield_func()for yield_val in gen_func: print yield_val
生成器函數(shù)每次執(zhí)行到y(tǒng)ield便會(huì)返回,但與普通函數(shù)不同的是yield返回時(shí)會(huì)保留當(dāng)前函數(shù)的執(zhí)行狀態(tài),再次被調(diào)用時(shí)可以從中斷的地方繼續(xù)執(zhí)行。
2.3 next與send
通過for和next可以遍歷生成器,而send則可以用于向生成器函數(shù)發(fā)送消息。
def yield_func(): for i in xrange(1, 3): x = yield i print 'yield_func',xgen_func = yield_func()print 'iter result: %d' % next(gen_func)print 'iter result: %d' % gen_func.send(100)
結(jié)果:
iter result: 1yield_func 100iter result: 2
簡(jiǎn)單分析一下執(zhí)行過程:
line_no 5 調(diào)用生成器函數(shù)yield_func得到函數(shù)生成器gen_func; line_no 6 使用next調(diào)用gen_func,此時(shí)才真正的開始執(zhí)行yield_func定義的代碼; line_no 3 執(zhí)行到y(tǒng)ield i,函數(shù)yield_func暫停執(zhí)行并返回當(dāng)前i的值1. line_no 6 next(gen_func)得到函數(shù)yield_func執(zhí)行到y(tǒng)ield i返回的值1,輸出結(jié)果iter result: 1; line_no 7 執(zhí)行g(shù)en_func.send(100); line_no 3 函數(shù)yield_func繼續(xù)執(zhí)行,并將調(diào)用者send的值100賦值給x; line_no 4 輸出調(diào)用者send接收到的值; line_no 3 執(zhí)行到y(tǒng)ield i,函數(shù)yield_func暫停執(zhí)行并返回當(dāng)前i的值2. line_no 7 執(zhí)行g(shù)en_func.send(100)得到函數(shù)yield_func運(yùn)行到y(tǒng)ield i返回的值2,輸出結(jié)果iter result: 2;新聞熱點(diǎn)
疑難解答
圖片精選