首頁>技術>

老闆下達了一個任務,說是要每天遍歷一百萬資料,找到日誌中重要地段的資訊,重新記錄存放?到底要怎麼搞呢?

小張回答說列表生成式不就可以嘛,老闆笑而不語。小王答曰用生成器吧。此時,老闆開心地點了點頭。

小張不明白,列表就可以很好處理的問題,為什麼要用生成器呢?

後來,小張明白了......

生成器 generator

我們知道,透過列表生成式,我們可以直接建立一個列表。但是,受客觀條件影響,我們使用的機器都是受到記憶體限制,所以列表容量肯定是有限的。這樣生成一個列表不僅佔用記憶體,如果我們只需要訪問一部分值,還會造成大量的記憶體浪費。

在Python2中可以做一個嘗試,感興趣的不妨試試。

開啟IDE互動介面,進入Python互動視窗,range(1000000)試試,不行可以range(10000000)再試試,那時候就可以很明顯的感受到記憶體計算的差別了。

正是因為這個缺點,在python3中對range進行了最佳化,range(10000)得到的結果是range(0,10000),這樣的一個生成式了。

所以,如果列表元素可以按照某種演算法推算出來,那我們是否可以在迴圈的過程中不斷推算出後續的元素呢?

像上面這個迴圈,每次迴圈只是+1而已,我們完全可以寫一個演算法,讓他執行一次就自動1,這樣就不必建立完整的,從而節省大量的空間。

在 Python中,這種一邊迴圈一邊計算後面元素的機制,稱為生成器: generator

生成器的生成

要建立一個 gonerator,有很多種方法。

第一種方法很簡,只要把一個列表生成式的改成()的形式,就建立了個gonerator

>>> [ x for x in range(10)][0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>> ( x for x in range(10))<generator object <genexpr> at 0x000002C103210E40>>>> g = ( x for x in range(10))

如上面的程式碼所示,我們可以直接得出列表的所有元素。那麼,生成器要怎麼訪問呢?

生成器的元素獲取

next()

生成器的元素,如果要一個一個打印出來,可以透過next()函,獲得generator的下一個返回值。

>>> g = ( x for x in range(10))>>> next(g)0>>> next(g)1>>> next(g)2>>> next(g)3>>> next(g)4>>> next(g)5>>> next(g)6>>> next(g)7>>> next(g)8>>> next(g)9>>> next(g)Traceback (most recent call last):  File "<pyshell#13>", line 1, in <module>    next(g)StopIteration

此時,我們每一次呼叫next就會生成一個新的元素,直到最後的時候會丟擲一個異常,而這個異常,我們可以通過後面的方法規避掉。

for迴圈

當然,上面這種不斷呼叫next(g)實在是太變態了。正確的方法是使用tor迴圈,因為 gonorator也是可選代(遍歷)物件。

g = ( x for x in range(10))for i in g:    print(i)0123456789

透過for迴圈來迭代它,就不需要關心會不會拋異常了。

生成器函式

特點:動態獲取資料,迴圈一次,計算一次,執行一次

生成器函式:具有yield語句。

案例:生成器的思想解決斐波那契數列

原始的方法

a = 0b = 1count = 0while count < 20:    temp = a    a = b    b = a + b    count += 1    print("b:",b)

生成器函式的方法

def fib(n):    a = 0    b = 1    count = 0    while count < n:        temp = a        a = b        b = a + b        count += 1        yield bfor i in fib(20):    print("i:", i)

那為什麼要用生成器呢?顯然,用生成器在逼格上高,效能高效,為什麼不用呢?

7
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 2021-08-14:給定兩個字串S和T,返回S的所有子序列中有多少個