生成器是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 語句的函式,就是生成器函式,呼叫後返...