為了理解什么是 yield,你必須理解什么是生成器巧还。在理解生成器之前,讓我們先走近迭代。
可迭代對象
當你建立了一個列表悍汛,你可以逐項地讀取這個列表,這叫做一個可迭代對象:
>>> mylist = [1, 2, 3]
>>> for i in mylist :
print(i)
mylist是一個可迭代的對象至会。當你使用一個列表生成式來建立一個列表的時候离咐,就建立了一個可迭代的對象:
>>> mylist = [x*x for x in range(3)]
>>> for i in mylist :
... print(i)
0
1
4
所有你可以使用 for .. in .. 語法的叫做一個迭代器:鏈表,字符串奉件,文件……你經(jīng)常使用它們是因為你可以如你所愿的讀取其中的元素宵蛀,但是你把所有的值都存儲到了內(nèi)存中,如果你有大量數(shù)據(jù)的話這個方式并不是你想要的县貌。
迭代對象的定義方式通常為:
1 # Using the generator pattern (an iterable)
2 class firstn(object):
3 def __init__(self, n):
4 self.n = n
5 self.num, self.nums = 0, []
6
7 def __iter__(self):
8 return self
9
10 # Python 3 compatibility
11 def __next__(self):
12 return self.next()
13
14 def next(self):
15 if self.num < self.n:
16 cur, self.num = self.num, self.num+1
17 return cur
18 else:
19 raise StopIteration()
20
21 sum_of_first_n = sum(firstn(1000000))
生成器
生成器是可以迭代的术陶,但是你只可以讀取它一次 ,因為它并不把所有的值放在內(nèi)存中煤痕,它是實時地生成數(shù)據(jù):
>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator :
... print(i)
0
1
4
看起來除了把 [] 換成 () 外沒什么不同梧宫。但是,你不可以再次使用 for i in mygenerator , 因為生成器只能被迭代一次:先計算出0摆碉,然后繼續(xù)計算1塘匣,然后計算4,一個跟一個的…
yield關(guān)鍵字
yield 是一個類似 return 的關(guān)鍵字巷帝,只是這個函數(shù)返回的是個生成器忌卤。
>>> def createGenerator() :
... mylist = range(3)
... for i in mylist :
... yield i*i
...
>>> mygenerator = createGenerator() # create a generator
>>> print(mygenerator) # mygenerator is an object!
<generator object createGenerator at 0xb7555c34>
>>> for i in mygenerator:
... print(i)
0
1
4
為了精通 yield ,你必須要理解:當你調(diào)用這個函數(shù)的時候,函數(shù)內(nèi)部的代碼并不立馬執(zhí)行 楞泼,這個函數(shù)只是返回一個生成器對象驰徊,這有點蹊蹺不是嗎笤闯。
那么,函數(shù)內(nèi)的代碼什么時候執(zhí)行呢棍厂?當你使用for進行迭代的時候.
現(xiàn)在到了關(guān)鍵點了颗味!
第一次迭代中你的函數(shù)會執(zhí)行,從開始到達 yield 關(guān)鍵字勋桶,然后返回 yield 后的值作為第一次迭代的返回值. 然后脱衙,每次執(zhí)行這個函數(shù)都會繼續(xù)執(zhí)行你在函數(shù)內(nèi)部定義的那個循環(huán)的下一次,再返回那個值例驹,直到?jīng)]有可以返回的捐韩。