自從 PEP 255 引入生成器以來,它就是 Python 中重要的一部分.html
生成器容許你定義一個有迭代器行爲的函數.python
它容許程序猿更快,更簡單而且以一個乾淨的方式建立一個迭代器.api
那麼什麼是迭代器呢,你或許會問?bash
iterator 迭代器是一個能夠被迭代的(循環)對象。它能夠抽象爲一個裝着數據同時有着可迭代對象的行爲的容器。或許你已經天天在使用一些可迭代的對象:諸如字符串,列表,字典或其它名字的對象.微信
一個迭代器是一個實現了迭代器接口 Iterator Protocol 的類。這個接口爲類提供了兩個方法: __iter__
和 __next__
.函數
嗯~回到上一步。你爲何想要建立一個迭代器呢?學習
當實例化後,迭代器並不會計算它每個項的值,他們只會等你訪問這些項的時候採起計算。這也就是衆所周知的惰性求值。ui
當你有一個很是大的數據集須要計算時,惰性求值是頗有用處的。它容許你立刻就能開始使用數據,儘管整個數據集還在計算中。lua
假設咱們想要得到小於某個最大值的全部素數。spa
咱們先定義一個函數,它能夠檢查一個數字是否爲素數:
def check_prime(number):
for divisor in range(2, int(number ** 0.5) + 1):
if number % divisor == 0:
return False
return True複製代碼
而後,咱們定義一個迭代器類,包含__iter__
和 __next__
方法。
class Primes:
def __init__(self, max):
self.max = max
self.number = 1
def __iter__(self):
return self
def __next__(self):
self.number += 1
if self.number >= self.max:
raise StopIteration
elif check_prime(self.number):
return self.number
else:
return self.__next__()複製代碼
Primes
類經過給定一個最大值來實例化。若是下一個素數比最大值 max
還要大,迭代器就會拋出一個 StopIteration
異常來把迭代器停掉。
當咱們請求迭代器中的下一個元素時,它會給 number
加 1 並檢查這個數字是否爲素數。若是不是,它會再次調用__next__
直到 number
成爲素數。一旦如此,迭代器就將這個數字返回。
經過使用迭代器,咱們並不會在內存中建立一個包含不少素數的列表。相反,咱們將會在每次請求下一個素數時纔去生成它。
讓咱們來試一試:
primes = Primes(100000000000)
print(primes)
for x in primes:
print(x)
......
<__main__.Primes object at 0x1021834a8>
2
3
5
7
11
...複製代碼
對 Primes
對象的每一次迭代都調用了 __next__
來生成下一個素數。
迭代器只能夠被迭代一輪。若是你嘗試再迭代 primes
一輪,它將不會返回任何值,表現得就像個空列表。
既然咱們已經知道了什麼是迭代器,以及怎麼製做一個迭代器,咱們接下來將繼續來看看生成器。
回想下,生成器函數容許咱們以一種更簡單的方式來建立迭代器。
生成器給 Python 引入了 yield
聲明。它用起來有點像 return
,由於它會返回一個值。
區別在於 yield
會保存函數的狀態。在函數下一次被調用時,將會從其離開的地方繼續執行,而且變量值也與它以前執行 yield
操做前相同。
若是把咱們的 Primes
迭代器轉換爲生成器,它看起來會像這樣:
def Primes(max):
number = 1
while number < max:
number += 1
if check_prime(number):
yield number
primes = Primes(100000000000)
print(primes)
for x in primes:
print(x)
......
<generator object Primes at 0x10214de08>
2
3
5
7
11
...複製代碼
如今真是太 pythonic 了!咱們還能再給力點嗎?
固然!咱們可使用 PEP 289 中介紹的生成器表達式。
這至關因而生成器的列表推導式。它用起來與列表推導式相同,不過表達式由 ()
包裹而不是 []
。
下面的表達式能夠代替咱們上面的生成器函數:
primes = (i for i in range(2, 100000000000) if check_prime(i))
print(primes)
for x in primes:
print(x)
......
<generator object <genexpr> at 0x101868e08>
2
3
5
7
11
...複製代碼
這就是 Python 生成器的美妙之處。
python開發等相關IT技術羣: 887934385 提供資料,部分相關源碼 共同探討
不經常使用q能夠掃如下二維碼添加助理客服小姐姐微信,經過後第一時間回覆
關注微信公衆號「 python社區營 」 第一時間學習更多知識