Yield關(guān)鍵字詳解

可迭代對象(Iterables)
??創(chuàng)建一個列表list時锅移,你可以逐個地讀取里面的每一項元素吕粗,這個過程稱之為迭代(iteration)</font>

>>> mylist = [1, 2, 3]
>>> for i in mylist:
...    print(i)
1
2
3

mylist是一個可迭代的對象纺荧,當(dāng)使用列表推導(dǎo)式創(chuàng)建一個列表時,它就是可迭代對象。</font>

>>> mylist = [x*x for x in range(3)]
>>> for i in mylist:
...    print(i)
0
1
4

任何可以使用在for...in...語句中的對象都叫做可迭代對象宙暇,例如:lists输枯、strings、files等等占贫。這些可迭代對象使用非常方便因為它們能如你所愿的盡可能的讀取其中的元素桃熄,但是你不得不把所有的值存儲在內(nèi)存中,當(dāng)它有大量元素的時候這并不一定總是你想要的型奥。
??dict對象已經(jīng)任何實現(xiàn)了_iter()或者_getitem()方法的類都是可迭代對象瞳收,此外,可迭代對象還可以用在zip厢汹、map等函數(shù)中螟深,當(dāng)一個可迭代對象作為參數(shù)傳遞給內(nèi)建函數(shù)iter()時,它會返回一個迭代器對象烫葬。通常沒有必要自己來處理迭代器本身或者手動調(diào)用iter()界弧,for語句會自動調(diào)用iter(),它會創(chuàng)建一個臨時的未命名的變量來持有這個迭代器用于循環(huán)期間搭综。</font>
迭代器(iterator)
??迭代器代表一個數(shù)據(jù)流對象夹纫,不斷重復(fù)調(diào)用迭代器的next()方法逐次的從返回數(shù)據(jù)流中的每一項,當(dāng)沒有更多數(shù)據(jù)可用時设凹,next()方法會拋出異常StopIteration。此時迭代器對象已經(jīng)枯竭了茅姜,之后調(diào)用next()方法都會拋出StopIteration闪朱。迭代器需要一個_iter_()方法用來返回迭代器本身,因此它也是一個可迭代的對象钻洒。</font>
生成器(Generators)
??生成器也是一個迭代器奋姿,但是你只可以迭代它們一次,不能重復(fù)迭代素标,因為它并沒有把所有的值存儲在內(nèi)存中称诗,而是實時地生成值:</font>

>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
...    print(i)
0
1
4

從結(jié)果上看用()代替[]的效果是一樣的,但是你不可能第二次執(zhí)行for i in mygenerator,因為生成器只能使用一次</font>

Yield
??yield是關(guān)鍵字,它類似于return头遭,只是函數(shù)會返回一個生成器寓免。

>>> class Bank(): # 創(chuàng)建銀行,構(gòu)建ATM機计维,只要沒有危機袜香,就可以不斷地每次從中取100
...    crisis = False
...    def create_atm(self):
...        while not self.crisis:
...            yield "$100"
>>> hsbc = Bank() # when everything's ok the ATM gives you as much as you want
>>> corner_street_atm = hsbc.create_atm()
>>> print(corner_street_atm.next())
$100
>>> print(corner_street_atm.next())
$100
>>> print([corner_street_atm.next() for cash in range(5)])
['$100', '$100', '$100', '$100', '$100']
>>> hsbc.crisis = True # 危機來臨,沒有更多的錢了
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> wall_street_atm = hsbc.create_atm() # 即使創(chuàng)建一個新的ATM鲫惶,銀行還是沒錢
>>> print(wall_street_atm.next())
<type 'exceptions.StopIteration'>
>>> hsbc.crisis = False # 危機過后蜈首,銀行還是空的,因為該函數(shù)之前已經(jīng)不滿足while條件
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> brand_new_atm = hsbc.create_atm() # 必須構(gòu)建一個新的atm,恢復(fù)取錢業(yè)務(wù)
>>> for cash in brand_new_atm:
...    print cash
$100
$100
$100
$100
$100
$100
$100
$100
$100
...

對于類似資源的訪問控制等場景欢策,生成器顯得很實用吆寨。
Itertools是你最好的朋友
??itertools模塊包含一些特殊的函數(shù)用來操作可迭代對象。曾經(jīng)想復(fù)制一個生成器踩寇?兩個生成器鏈接啄清?在內(nèi)嵌列表中一行代碼處理分組?不會創(chuàng)建另外一個列表的Map/Zip函數(shù)姑荷?你要做的就是import itertools 盒延。無例子無真相,我們來看看4匹馬賽跑到達終點所有可能的順序:

>>> horses = [1, 2, 3, 4]
>>> races = itertools.permutations(horses)
>>> print(races)
<itertools.permutations object at 0xb754f1dc>
>>> print(list(itertools.permutations(horses)))
[(1, 2, 3, 4),
 (1, 2, 4, 3),
 (1, 3, 2, 4),
 (1, 3, 4, 2),
 (1, 4, 2, 3),
 (1, 4, 3, 2),
 (2, 1, 3, 4),
 (2, 1, 4, 3),
 (2, 3, 1, 4),
 (2, 3, 4, 1),
 (2, 4, 1, 3),
 (2, 4, 3, 1),
 (3, 1, 2, 4),
 (3, 1, 4, 2),
 (3, 2, 1, 4),
 (3, 2, 4, 1),
 (3, 4, 1, 2),
 (3, 4, 2, 1),
 (4, 1, 2, 3),
 (4, 1, 3, 2),
 (4, 2, 1, 3),
 (4, 2, 3, 1),
 (4, 3, 1, 2),
 (4, 3, 2, 1)]

理解迭代器的內(nèi)部機理
??迭代是操作可迭代對象(實現(xiàn)了_iter()方法)和迭代器(實現(xiàn)了_next()方法)的過程鼠冕√硭拢可迭代對象是任何你可以從其中得到一個迭代器對象的任意對象(調(diào)用內(nèi)建函數(shù)_iter_()),迭代器是能讓你在可迭代對象上進行迭代的對象懈费。
??一個帶有 yield 的函數(shù)就是一個 generator计露,它和普通函數(shù)不同,生成一個 generator 看起來像函數(shù)調(diào)用憎乙,但不會執(zhí)行任何函數(shù)代碼票罐,直到對其調(diào)用 next()(在 for 循環(huán)中會自動調(diào)用 next())才開始執(zhí)行。雖然執(zhí)行流程仍按函數(shù)的流程執(zhí)行泞边,但每執(zhí)行到一個 yield 語句就會中斷该押,并返回一個迭代值,下次執(zhí)行時從 yield 的下一個語句繼續(xù)執(zhí)行阵谚〔侠瘢看起來就好像一個函數(shù)在正常執(zhí)行的過程中被 yield 中斷了數(shù)次,每次中斷都會通過 yield 返回當(dāng)前的迭代值梢什。
yield 的好處是顯而易見的奠蹬,把一個函數(shù)改寫為一個 generator 就獲得了迭代能力,比起用類的實例保存狀態(tài)來計算下一個 next() 的值嗡午,不僅代碼簡潔囤躁,而且執(zhí)行流程異常清晰。
使用Yield的一個例子荔睹,從文件讀取內(nèi)容狸演。
如果直接對文件 對象調(diào)用read()方法,會導(dǎo)致不可預(yù)測的內(nèi)存占用僻他。好的方法是利用固定長度的緩沖區(qū)來不斷讀取文件內(nèi)容严沥。通過yield,我們不在需要編寫讀取文件的迭代類中姜,就可以輕松實現(xiàn)文件讀认:

 def read_file(fpath): 
    BLOCK_SIZE = 1024 
    with open(fpath, 'rb') as f: 
        while True: 
            block = f.read(BLOCK_SIZE) 
            if block: 
                yield block 
            else: 
                return
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末跟伏,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子翩瓜,更是在濱河造成了極大的恐慌受扳,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兔跌,死亡現(xiàn)場離奇詭異勘高,居然都是意外死亡,警方通過查閱死者的電腦和手機坟桅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門华望,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人仅乓,你說我怎么就攤上這事赖舟。” “怎么了夸楣?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵宾抓,是天一觀的道長。 經(jīng)常有香客問我豫喧,道長石洗,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任紧显,我火速辦了婚禮讲衫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘孵班。我一直安慰自己涉兽,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布重父。 她就那樣靜靜地躺著,像睡著了一般忽匈。 火紅的嫁衣襯著肌膚如雪房午。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天丹允,我揣著相機與錄音郭厌,去河邊找鬼。 笑死雕蔽,一個胖子當(dāng)著我的面吹牛折柠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播批狐,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼扇售,長吁一口氣:“原來是場噩夢啊……” “哼前塔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起承冰,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤华弓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后困乒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寂屏,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年娜搂,在試婚紗的時候發(fā)現(xiàn)自己被綠了迁霎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡百宇,死狀恐怖考廉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情恳谎,我是刑警寧澤芝此,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站因痛,受9級特大地震影響婚苹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鸵膏,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一膊升、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧谭企,春花似錦廓译、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至盹廷,卻和暖如春征绸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背俄占。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工管怠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人缸榄。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓渤弛,卻偏偏與公主長得像,于是被迫代替她去往敵國和親甚带。 傳聞我的和親對象是個殘疾皇子她肯,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

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