1. 程式人生 > 實用技巧 >Python11月28日

Python11月28日

生成器

通過列表生成式,我們可以直接建立一個列表。但是,受到記憶體限制,列表容量肯定是有限的。而且,建立一個包含100萬個元素的列表,不僅佔用很大的儲存空間,如果我們僅僅需要訪問前面幾個元素,那後面絕大多數元素佔用的空間都白白浪費了。

所以,如果列表元素可以按照某種演算法推算出來,那我們是否可以在迴圈的過程中不斷推算出後續的元素呢?這樣就不必建立完整的list,從而節省大量的空間。在Python中,這種一邊迴圈一邊計算的機制,稱為生成器:generator。

要建立一個generator,有很多種方法。第一種方法很簡單,只要把一個列表生成式的[]改成(),就建立了一個generator:

>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>


建立Lg的區別僅在於最外層的[]()L是一個list,而g是一個generator。


我們怎麼打印出generator的每一個元素呢?
第一個是用next()來實現,但是這個方法太變態了
所以我們使用第二種方法:使用for迴圈,因為generator也是可迭代物件
# g=(x * x for x in range(1,11))
# for i in g:
# print(i)



迭代器

可以直接作用於for迴圈的資料型別有以下幾種:


一類是集合資料型別,如listtupledictsetstr等;


一類是generator,包括生成器和帶yield的generator function。


這些可以直接作用於for迴圈的物件統稱為可迭代物件:Iterable

可以使用isinstance()判斷一個物件是否是Iterable物件:

from collections.abc import Iterable
>>> isinstance([], Iterable)
True

可以被next()函式呼叫並不斷返回下一個值的物件稱為迭代器:Iterator


可以使用isinstance()判斷一個物件是否是Iterator物件:


>>> from collections.abc import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True

生成器都是Iterator物件,但listdictstr雖然是Iterable,卻不是Iterator


listdictstrIterable變成Iterator可以使用iter()函式:


>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True






凡是可作用於for迴圈的物件都是Iterable型別;

凡是可作用於next()函式的物件都是Iterator型別,它們表示一個惰性計算的序列;

集合資料型別如listdictstr等是Iterable但不是Iterator,不過可以通過iter()函式獲得一個Iterator物件