python生成器

基礎(chǔ)知識

生成器是python的一個特別特的特性衣式,在許多場合都有重要應(yīng)用爪膊。比如range函數(shù)產(chǎn)生的就是一個生成器捡遍。其主要的好處就是降低了內(nèi)存的占用。為什么呢眨业?拿range函數(shù)來講吧急膀,它的目的是生成一系列的數(shù)。假如我們想生成一列數(shù)0龄捡,1卓嫂,2,3墅茉,4命黔,則(以下兩個緊跟的代碼塊中呜呐,第一個是實際的代碼,第二個是輸出)

range(5)
range(0, 5)

欸悍募?怎么回事蘑辑,輸出的不是0,1坠宴,2洋魂,3,4,而是一個函數(shù)喜鼓。這個函數(shù)實際上便是一個生成器副砍。我們可以采用下面的方法把它展開

list(range(5))
[0, 1, 2, 3, 4]

或者使用一個for循環(huán)

for i in range(5):
    print(i)
0
1
2
3
4

生成器常常與for循環(huán)結(jié)合使用。在上述循環(huán)過程中庄岖,每循環(huán)一步豁翎,range產(chǎn)生一個數(shù),直至range拋出一個結(jié)束的異常隅忿,for捕獲異常后結(jié)束循環(huán)心剥。
通過運行步驟,我們可以明白生成器節(jié)省空間的道理所在背桐。range并沒有一次性將數(shù)列都生成优烧,而是逐漸生成。

自制生成器

為了進一步掌握生成器的編寫方式链峭,我們一起來實現(xiàn)range函數(shù)畦娄。當(dāng)然這不一定是python內(nèi)部的實現(xiàn)。如前文所述弊仪,range函數(shù)的作用是生成一列數(shù)熙卡。range的原本功能可以指定起始數(shù)、終止數(shù)和間隔撼短。為了演示突出生成器的重點再膳,我們將實現(xiàn)一個簡化版的range挺勿,只給一個輸入n曲横,讓其生成由0到n-1的數(shù)。并且不瓶,這個函數(shù)只是我們自己使用禾嫉,就不做輸入合法性檢查了。閑言少敘蚊丐,先看代碼

def _range(n):
    step = 0
    while step < n:
        yield step
        step = step + 1
print(list(_range(5)))
[0, 1, 2, 3, 4]

注釋講解版函數(shù)如下

# 為了與python內(nèi)置range函數(shù)進行區(qū)分熙参,我們將其命名為_range.
# 那么如果你說我就不區(qū)分會怎么樣?如果不區(qū)分的話麦备,那么咱在這里定義的函數(shù)便會覆蓋原函數(shù)孽椰。
def _range(n):
    # 采用一個變量暫存步數(shù)
    step = 0
    # 采用一個while循環(huán)昭娩,產(chǎn)生數(shù)據(jù)。
    # 當(dāng)步數(shù)小于輸入值n時黍匾,執(zhí)行循環(huán)迭代
    while step < n:
        # 這是迭代器最關(guān)鍵的一步栏渺。yield表示輸出此洲。
        # 每當(dāng)調(diào)用一次_range缩擂,便會執(zhí)行到一個yield處著瓶,產(chǎn)生一個數(shù)據(jù)漂彤,同時暫停函數(shù)運行祈争,直至再次調(diào)用苟弛。
        # 稍后會給出另外一個版本备典,加強大家在這方面的理解诫欠。
        yield step
        # 當(dāng)再次調(diào)用時升薯,會從這里開始莱褒,而非函數(shù)頭部。步數(shù)加1涎劈,繼續(xù)迭代
        step = step + 1
# 調(diào)用并將產(chǎn)生的數(shù)據(jù)展開后輸出
print(list(_range(5)))

為了進一步加強大家對生成器的理解保礼,接下來我們將上述版本稍作修改。我們想要產(chǎn)生一個0责语,0炮障,1,1坤候,2胁赢,2.。白筹。智末。n-1,n-1的數(shù)列。該如何是好徒河?且看

def _range(n):
    step = 0
    while step < n:
        yield step
        yield step
        step = step + 1
print(list(_range(5)))
[0, 0, 1, 1, 2, 2, 3, 3, 4, 4]

同時采用了兩個yield系馆,每當(dāng)對_range函數(shù)調(diào)用一次,便從函數(shù)暫停的位置運行至下一個yield處顽照,產(chǎn)生數(shù)據(jù)由蘑,隨后輸出。
接下來再舉一個例子代兵。我們產(chǎn)生一個0尼酿,0,1植影,0裳擎,1,2思币,0鹿响,1羡微,2,3等等惶我。這就要用到y(tǒng)ield from這個語法了拷淘。它是生成器中的生成器。

def _range(n):
    step = 0
    while step < n:
        # range是另外一個生成器指孤,yield from表示函數(shù)運行到此處時启涯,進入range函數(shù)繼續(xù)執(zhí)行,直至range函數(shù)執(zhí)行完畢恃轩。
        yield from range(step)
        step = step + 1
print(list(_range(5)))
[0, 0, 1, 0, 1, 2, 0, 1, 2, 3]

如果不用yield from會怎么樣结洼?想想。答案如下:

def _range(n):
    step = 0
    while step < n:
        # range是另外一個生成器叉跛,yield from表示函數(shù)運行到此處時松忍,進入range函數(shù)繼續(xù)執(zhí)行,直至range函數(shù)執(zhí)行完畢筷厘。
        yield range(step)
        step = step + 1
print(list(_range(5)))
for i in _range(5):
    print(i)
for i in _range(5):
    print(list(i))
[range(0, 0), range(0, 1), range(0, 2), range(0, 3), range(0, 4)]
range(0, 0)
range(0, 1)
range(0, 2)
range(0, 3)
range(0, 4)
[]
[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]

一個實際應(yīng)用

不知道大家對生成器的基本原理及用法是否理解鸣峭?下面我用一個更為實際的例子講解生成器的妙用。
我在做數(shù)據(jù)處理時酥艳,單個數(shù)據(jù)文件可能非常大摊溶,直接讀進內(nèi)存很困難。這時候充石,便可采用生成器逐步讀取處理莫换。如

import os
def getFrame(filename):
    pos = 0
    frameSize = 100
    fullSize = os.path.getsize(filename)
    with open(filename, 'rb') as fid:
        while pos < fullSize:
            fid.seek(pos)
            yield fid.read(frameSize)
            pos = pos + frameSize

for frame in getFrame('SomeFilePath'):
    print(frame)

對于以上代碼,我不過多講解骤铃。大家對于其中有不明白的地方拉岁,可以自行查找?guī)椭謨曰蛘甙俣取H绻€有不明白的地方惰爬,可以留言喊暖。其中大家可以重點理解with用法,這是在文件讀取時常用并且非常好用的一個語法撕瞧。
jupyter notebook原文件位于https://gitee.com/bolang/python-lesson.git

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末陵叽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子风范,更是在濱河造成了極大的恐慌咨跌,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件硼婿,死亡現(xiàn)場離奇詭異,居然都是意外死亡禽车,警方通過查閱死者的電腦和手機寇漫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門刊殉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人州胳,你說我怎么就攤上這事记焊∷ㄗ玻” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵瓤湘,是天一觀的道長瓢颅。 經(jīng)常有香客問我,道長弛说,這世上最難降的妖魔是什么挽懦? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮木人,結(jié)果婚禮上信柿,老公的妹妹穿的比我還像新娘。我一直安慰自己醒第,他們只是感情好渔嚷,可當(dāng)我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著稠曼,像睡著了一般圃伶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蒲列,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天窒朋,我揣著相機與錄音,去河邊找鬼蝗岖。 笑死侥猩,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的抵赢。 我是一名探鬼主播欺劳,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼铅鲤!你這毒婦竟也來了划提?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤邢享,失蹤者是張志新(化名)和其女友劉穎鹏往,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體骇塘,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡伊履,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年韩容,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唐瀑。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡群凶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出哄辣,到底是詐尸還是另有隱情请梢,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布力穗,位于F島的核電站毅弧,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏睛廊。R本人自食惡果不足惜形真,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望超全。 院中可真熱鬧咆霜,春花似錦、人聲如沸嘶朱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至财异,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間戳寸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工袖瞻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留拆吆,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓霉晕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子娄昆,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 總目錄:http://www.reibang.com/p/e406a9bc93a9 Python - 子目錄:h...
    寒暄_HX閱讀 311評論 0 3
  • 文章來源:python 生成器和迭代器有這篇就夠了 什么是迭代器萌焰? 迭代器是訪問集合元素的一種方式谷浅。迭代器對象從集...
    YYL07閱讀 543評論 0 4
  • 今天開始又要重新關(guān)注python了一疯,關(guān)注一些高級特性。第一part:生成器(generator)墩邀。 學(xué)習(xí)新東西我都...
    泡泡_e661閱讀 4,426評論 0 0
  • 姓名:曾國強 學(xué)號:19021210984 轉(zhuǎn)載自https://zhuanlan.zhihu.com/p/768...
    不忘初心_ecca閱讀 83評論 0 0
  • 生成器(generator)在Python中是為了解決內(nèi)存不足而提出的一種方法,例如,我們要創(chuàng)建一個包含10萬個元...
    貝塔Man閱讀 185評論 0 0