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