Python的生成器

2021-07-30 14:12:04 字數 3927 閱讀 4499

生成器是python新引入的概念,由於歷史原因,它也叫做簡單生成器。它和迭代器可能近幾年來引入的最大的兩個特徵。但是,生成器的概念則要更高階一些,需要花費一些功夫才能理解它是如何工作的以及有什麼用處。生成器可以幫助讀者寫出優雅的**,當然,編寫任何程式時不使用生成器也是可以的。

生成器是一種普通的函式語法定義的迭代器。它的工作方式可以用例子來很好地展現。

1、建立迭代器

建立乙個生成器就象建立函式一樣。接下來用乙個例子說明生成器的知識。首先建立乙個巢狀列表的函式。引數是乙個例子,如下所示:

nested=[[1,2],[3,4],[5]]

換句話說技術第乙個列表的列表。函式應該按順序列印列表中的數字。解決的方法如下:

def flattern(nested):

for sublist in nested:

for element in sublist:

yield element

print(element)

這個函式的大部分是很簡單的。首先迭代提供的巢狀列表中的所有子列表,然後按順序迭代子列表中的元素。如果最後一行是print(element)的話,那麼就容易理解了,不是嗎?

這裡的yield語句是新知識。任何包含yield語句的函式稱為生成器。除了名字不同以外,它的行為和普通的函式也有很大的差別。這就在於它不像return哪樣返回值,而是每次產生多個值。每次產生乙個值,函式就會被凍結:即函式停在哪點等待被重新喚醒。函式被重新喚醒後就從停止的哪點開始執行。

2、遞迴生成器

上訴建立的生成器只能處理兩層巢狀,為了處理巢狀使用了兩個for迴圈。哪如何處理任意層巢狀的呢?每層巢狀需要增加乙個for迴圈,但因為不知道幾層巢狀,所以必須把解決方案變得靈活。用遞迴能解決此問題。

def flatten(nested):

try:

for sublist in nested:

for element in flatten(sublist):

yield element

except typeerror:

yield nested

當flattern被呼叫時,有兩種可能性:基本情況和需要遞迴的情況。

在基本情況中,函式被告知展開乙個元素,這種情況下,for迴圈會引起乙個typeerror異常,生成器會產生乙個元素。

需要遞迴情況中,展開還是乙個列表。程式會遍歷所有的字列表,並對他們呼叫flattern,然後使用使用另乙個for迴圈來產生被展開的字列表中的所有元素。

>>>list(flattern([[[1],2],3,4,[5,[6,7]],8]))

[1,2,3,4,5,6,7,8]

如果輸入的函式類似於字串的物件,迭代對結果產生干擾(但不會引發typeerror),為了處理這種情況,則必須在生成器中的開始新增乙個檢查語句。試著將傳入的物件和乙個字元拼接,看看會不會引發typeerror,這是檢查乙個物件是不是類似於字串的最簡單,最快捷的方法。下面是加入了檢查語句的生成器:

def flatten(nested):

try:

try:nested+' '

except typeerror:pass

else:raise typeerror

for sublist in nested:

for element in flatten(sublist):

yield element

except typeerror:

yield nested

如果表示式nest+『 』引發了乙個typeerror,它就會被忽略。然後如果沒有引發typeerror,那麼內層try語句中else子句就會引發乙個typeerror異常。這就會按照原來的樣子生成類似於字串的物件(在except子句的外面).

例子展示:

>>>list(flatten(['foo',['bar',['baz']]]))

['foo','bar','baz']

3、通用生成器

如果到目前的所有例子你看懂了,哪應該或多或少地知道如何使用生氣器。生成器是乙個包含yield關鍵字的函式。當它被呼叫時,在函式體中的**,而會返回乙個迭代器。每次請求乙個值,就會執行生成器中的**,知道遇見乙個yield或者return語句。yield語句意味著應該生成乙個值。return語句意味著生成器要停止執行(不再生成任何東西,return語句只有乙個生成器中使用時才能進行無引數呼叫)。

換句話說,生成器是由兩部分組成:生成器的函式和生成器的迭代器。生成器的函式是用def語句定義的,包含yield的部分,生成器的迭代器是這個函式返回的部分。按一種不是很準確的說法。兩個實體經常被當做乙個,合起來叫做生成器。

>>>def ******_generator():

yield 1

>>>******_generator

>>>******_generator()

生成器的函式返回迭代器可以像其他的迭代器那樣使用。

4、生成器方法

生成器的新特徵是在開始執行後為生成器提供值得能力。表現為生成器和「外部世界」進行交流的渠道,要注意下面兩點。

(1)外部作用域訪問生成器的send方法,就像訪問next方法一樣,只不過前者使用乙個引數(要傳送的『』訊息『』————任意物件)。

(2)在內部則掛起生成器,yield現在作為表示式而不是語句使用,換句話說,當生成器重新執行的時候,yield方法返回乙個值,也就是外部通過send發放傳送的值。如果next方法被使用,那麼yield方法返回none。

!!!使用send方法只有在生成器掛起之後才有意義(也就是說yield函式第一次被執行之後)。如果在此之前需要給生成器提供更多資訊,那麼只需要使用生成器函式的引數。如果真想對剛剛啟動的生成器使用send方法,那麼可以將none作為其引數進行呼叫。

例:

def repeater(value):

while true:

new=(yield value)

if new is not none:value=new

使用方法如下:

r=repeater(42)

r.next()

r.send("hello,world!")

"hello,world!"

生成器還有其他兩個方法:

(3)throw方法用於在生成器內引發乙個異常

(4)close方法用於停止生成器。

close方法也是建立在異常的基礎上的。它在yield執行處引發乙個generatorexit異常,所以如果需要在生成器內進行**清理的話,則可以將yield語句放在try/finally語句中。

5、模擬生成器

生成器在舊版本中的python中是不可用的。下面介紹的使用普通函式模擬生成器。

先從生成器的**開始。首先下面語句放在函式圖的開始處:

resulr=[ ]

然後將下面這種形式的**:

yield some_expression

用下面的語句替換:

最後,在函式的末尾,新增下面的語句:

return result

此方法適用於大多數的生成器(比如,不能用於乙個無限的生成器,當然不能把它的值放入列表中).

下面是flattern生成器用普通函式的版本:

def flatten(nested):

result=

try:

try:nested+' '

except typeerror:pass

else:raise typeerror

for sublist in nested:

for element in flatten(sublist):

except typeerror:

return result

python 生成器作用 Python生成器

生成器介紹 在函式內部包含yield關鍵字,那麼該函式執行的結果是生成器,生成器就是迭代器。生成器的功能 把函式結果做成迭代器 以一種優雅的方式封裝好iter,next 提供了一種自己定義迭代器的方式。使用生成器建立乙個迭代器 def a print a yield 11 使用yield,執行後返回...

python生成器好處 Python生成器筆記

python中三大器有迭代器,生成器,裝飾器,本文主要講述生成器。主要從生成器的概念,本質,以及yield關鍵字的使用執行過程。本質 生成器是一類特殊的迭代器,使用了yield關鍵字的函式不再是函式,而是生成器。使用了yield的函式就是生成器 1.yield關鍵字有兩點作用 1.1 yield語句...

python生成器函式 Python 生成器函式

一 生成器 生成器指的是生成器物件,可由生成器表示式得到,也可使用 yield 關鍵字得到乙個生成器函式,呼叫這個函式得到乙個生成器物件 生成器物件,是乙個可迭代物件,是乙個迭代器 生成器物件,是延遲計算 惰性求值的 1.1 生成器函式 函式體重包含 yield 語句的函式,就是生成器函式,呼叫後返...