python yield詳解

迭代器(Iterator)python

  爲了理解yield是什麼,首先要明白生成器(generator)是什麼,在講生成器以前先說說迭代器(iterator),當建立一個列表(list)時,你能夠逐個的讀取每一項,這就叫作迭代(iteration)。函數

  例子:工具

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

Mylist就是一個迭代器,無論是使用複雜的表達式列表,仍是直接建立一個列表,都是可迭代的對象。對象

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

你可使用「for··· in ···」來操做可迭代對象,如:list,string,files,這些迭代對象很是方便咱們使用,由於你能夠按照你的意願進行重複的讀取。可是你不得不預先存儲全部的元素在內存中,那些對象裏有不少元素時,並非每一項都對你有用。blog

 

生成器(Generators)接口

生成器一樣是可迭代對象,可是你只能讀取一次,由於它並無把全部值存放內存中,它動態的生成值:ip

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

使用()和[]結果是同樣的,可是,第二次執行「 for in mygenerator」不會有任何結果返回,由於它只能使用一次。首先計算0,而後計算1,以後計算4,依次類推。內存

 

 

Yieldgenerator

Yield是關鍵字, 用起來像return,yield在告訴程序,要求函數返回一個生成器。string

>>> def createGenerator():
...     mylist = range(3)
...     for i in mylist:
...        yield i * i 
...     
>>> mygenerator = createGenerator()
>>> print mygenerator
<generator object createGenerator at 0x7fd61e8ba190>
>>> for i in mygenerator:
...     print i 
... 
0
1
4

       這個示例自己沒什麼意義,可是它很清晰地說明函數將返回一組僅能讀一次的值,要想掌握yield,首先必須理解的是:當你調用生成器函數的時候,如上例中的createGenerator(),程序並不會執行函數體內的代碼,它僅僅只是返回生成器對象,這種方式頗爲微妙。函數體內的代碼只有直到每次循環迭代(for)生成器的時候纔會運行。

  函數第一次運行時,它會從函數開始處直到碰到yield時,就返回循環的第一個值,而後,交互的運行、返回,直到沒有值返回爲止。若是函數在運行可是並無遇到yield,就認爲該生成器是空,緣由多是循環終止,或者沒有知足任何」if/else」

 

>>> class Bank(): # 建立銀行,構造ATM機
...    crisis = False
...    def create_atm(self) :
...        while not self.crisis :
...            yield "$100"
>>> hsbc = Bank() # 沒有危機時,你想要多少,ATM就能夠吐多少
>>> 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.ceate_atm() # 新建ATM,銀行仍然沒錢
>>> print(wall_street_atm.next())
<type 'exceptions.StopIteration'>
>>> hsbc.crisis = False # 麻煩就是,即便危機事後銀行仍是空的
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> brand_new_atm = hsbc.create_atm() # 構造新的ATM,恢復業務
>>> for cash in brand_new_atm :
...    print cash
$100
$100
$100
$100
$100
$100
$100
$100
$100

迭代工具,你最好的朋友

 

迭代工具模塊包含了操作指定的函數用於操做迭代器。想複製一個迭代器出來?連接兩個迭代器?以one liner(這裏的one-liner只需一行代碼能搞定的任務)用內嵌的列表組合一組值?不使用list建立Map/Zip?···,你要作的就是 import itertools,舉個例子吧:

四匹馬賽跑到達終點排名的全部可能性:

>>> hroses = [1,2,3,4]
>>> races = itertools.permutations(hroses)
>>> print races
<itertools.permutations object at 0x7fd61e893890>
>>> print (list(itertools.permutations(hroses)))
[(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)]
>>> 

理解迭代的內部機制:

迭代(iteration)就是對可迭代對象(iterables,實現了__iter__()方法)和迭代器(iterators,實現了__next__()方法)的一個操做過程。可迭代對象是任何可返回一個迭代器的對象,迭代器是應用在迭代對象中迭代的對象,換一種方式說的話就是:iterable對象的__iter__()方法能夠返回iterator對象,iterator經過調用next()方法獲取其中的每個值(譯者注),讀者能夠結合Java API中的 Iterable接口和Iterator接口進行類比。

相關文章
相關標籤/搜索