首先,先看**:
def
add(s, x):
return s + x
defgen
():for i in range(4):
yield i
base = gen()
for n in [1, 10]:
base = (add(i, n) for i in base)
print list(base)
輸出的結果是【20,21,22,23】,也許你會有其他答案
那麼怎麼得出來的呢?
說到生成器,你必須要知道迭代器(iterator),它只能迭代一次,且遵從迭代器協議:
1.定義了__iter__
方法,但是必須返回自身
2.定義了next方法,在python3中是__next__
,用來返回下乙個值,當沒有資料可返回時,會丟擲乙個stopiteration錯誤
3.可以保持當前的狀態
樣例
自定義iterator 如何讓自定義的類的物件成為迭代器物件,其實就是定義__iter__
和next
方法:
class
dataiter
(object):
def__init__
(self, *args):
self.data = list(args)
self.ind = 0
def__iter__
(self):
#返回自身
return self
defnext
(self):
# 返回資料
if self.ind == len(self.data):
raise stopiteration
else:
data = self.data[self.ind]
self.ind += 1
return data
那麼為什麼可以使用for來迭代迭代器物件呢,原因就是for替我們做了next的活,以及接收stopiteration的處理。
迭代器大概如此,下面介紹主角:優雅的迭代器——生成器(generator)。
首先,因為生成器遵循了迭代器協議,所以生成器也是一種迭代器
建立生成器的方式有兩種:
1.yield
生成器函式跟普通函式只有一點不一樣,就是把 return 換成yield,其中yield是乙個語法糖,內部實現了迭代器協議,同時保持狀態可以掛起。如下:
記住一點,yield是資料的生產者,而諸如for等是資料的消費者。
def
gen():
print
'begin: generator'
i = 0
while
true:
print
'before return ', i
yield i
i += 1
print
'after return ', i
a = gen()
a.next()
首先,看到while true
時不比驚慌,它只會乙個乙個被動的執行,不會主動去執行。當呼叫gen()時,並沒有真實執行函式,而是只是返回了乙個生成器物件。執行第一次a.next()時,才真正執行函式,執行到yield乙個返回值,然後就會掛起,保持當前的名字空間等狀態。然後等待下一次的呼叫,從yield的下一行繼續執行。說白了就是你需要資料(被檢索)的時候,才會執行。
2.生成器表示式
a = (i for i in range(10))
生成器表示式會建立乙個生成器,而且生成器有個特點就是惰性計算, 只有在被檢索時候,才會被賦值,正如上邊所說。
再來看乙個例子:
def
multipliers
():return (lambda x : i * x for i in range(4))
print [m(2) for m in multipliers()]
輸出結果為【0,2,4,6】,不清楚則可以看以下等價寫法:
def
multipliers
():for x in range(4):
defcd(i):
return x*i
yield cd
print [m(2) for m in multipliers()]
但是需要注意以下例子
def
multipliers
():return [lambda x : i * x for i in range(4)]
print [m(2) for m in multipliers()]
此例輸出為【6,6,6,6】而不是【0,2,4,6】,原因是因為閉包的延遲繫結。當迴圈結束時,i 的值已經是3, 此時結果都是6。不清楚可以看以下等價寫法:
def
multipliers
(): res =
for i in range(4):
definner
(j):
return j * i
return res
print [m(2) for m in multipliers()]
乙個解決的方法便是,使用預設引數繫結數值,如下:
def
multipliers
(): res =
for i in range(4):
definner
(j, i = i):
return j * i
return res
print [m(2) for m in multipliers()]
或者:
def
multipliers
():return [lambda x, i = i : i * x for i in range(4)]
print [m(2) for m in multipliers()]
參考頁: python 中關於推導式生成器的一些總結
推導式 可以理解為是資料生成方式或者是處理方式 型別 列表,元組,字串,字典,集合 外部包裝的括號決定了返回值型別的 定義 表示式 for迴圈 if語句 1 對列表中的每項元素進行立方運算 變換功能 a 1,2,3,4,5,6,7,8,9,10 b x 3 for x in a print a pr...
Python練習 生成器 乙個生成器被坑的體無完膚
如下,盡可能獨立閱讀 1 2 from urllib.request import urlopen 匯入乙個包,這就是egon留的乙個坑 3def get url 這是為了保證題目的原裝性所以還是要有乙個url引數,實際上完全沒有這個必要 4def index 可能是egon想要我們更加熟悉閉包的概...
Python的生成器(一)
python的生成器是其有魅力的地方之一,它的好處是不用一開始就生成一大堆的資料,而是在需要的時候才計算出資料,我們首先先來看一下怎樣建立乙個生成器 建立生成器很簡單,我們來看第一種 x i for i in range 11 看一下是不是很簡單,看起來是不是很熟悉,怎麼像是列表生成式,是的,但是需...