先說迭代器,對於string
、list
、dict
、tuple
等這類容器物件,使用for
迴圈遍歷是很方便的。在後台for
語句對容器物件呼叫iter()
函式,iter()
是python的內建函式。iter()
會返回乙個定義了next()
方法的迭代器物件,它在容器中逐個訪問容器內元素,next()
也是python的內建函式。在沒有後續元素時,next()
會丟擲乙個stopiteration
異常,通知for
語句迴圈結束。比如:
>>> s = 'abc'
>>> it = iter(s)
>>> it
>>> next(it)
'a'>>> next(it)
'b'>>> next(it)
'c'>>> next(it)
traceback (most recent call last):
file "", line 1, in stopiteration
上面說的都是python自帶的容器物件,它們都實現了相應的迭代器方法,那如果是自定義類需要遍歷怎麼辦?方法很簡單,對這個類aclass,實現乙個__iter__(self)
方法,使其返回乙個帶有__next__(self)
方法的物件就可以了。如果你在aclass剛好也定義了__next__(self)
方法(一般使用迭代器都會定義),那在__iter__
裡只要返回self
就可以。廢話少說,先上**:
class fib(object):
def __init__(self, max):
super(fib, self).__init__()
self.max = max
def __iter__(self):
self.a = 0
self.b = 1
return self
def __next__(self):
fib = self.a
if fib > self.max:
raise stopiteration
self.a, self.b = self.b, self.a + self.b
return fib
def main():
fib = fib(100)
for i in fib:
print(i)
if __name__ == '__main__':
main()
簡單講下**會幹什麼,定義了乙個fib類,用於生成fibonacci序列。用for遍歷時會逐個列印生成的fibonacci數,max是生成的fibonacci序列中數字大小的上限。
在類的實現中,定義了乙個__iter__(self)
方法,這個方法是在遍歷時被iter()
呼叫,返回乙個迭代器。因為在遍歷的時候,是直接呼叫的python內建函式iter()
,由iter()
通過呼叫__iter__(self)
獲得物件的迭代器。有了迭代器,就可以逐個遍歷元素了。而逐個遍歷的時候,也是使用內建的next()
函式通過呼叫物件的__next__(self)
方法對迭代器物件進行遍歷。所以要實現__iter__(self)
和__next__(self)
。而且因為實現了__next__(self)
,所以在實現__iter__(self)
的時候,直接返回self就可以。
為了更好理解,我再簡單重複下上面說的那一段:在迴圈遍歷自定義容器物件時,會使用python內建函式iter()
呼叫遍歷物件的__iter__(self)
獲得乙個迭代器,之後再迴圈對這個迭代器使用next()
呼叫迭代器物件的__next__(self)
。__iter__
只會被呼叫一次,而__next__
會被呼叫 n 次。
下面說生成器。
生成器(generator)是建立迭代器的簡單而強大的工具。它們寫起來就像是正規的函式,只是在需要返回資料的時候使用yield
語句。每次next()
被呼叫時,生成器會返回它脫離的位置(它記憶語句最後一次執行的位置和所有的資料值)。以下示例演示了生成器可以很簡單的建立出來:
>>> def reverse(data):
... for index in range(len(data)-1, -1, -1):
... yield data[index]
...
>>> for char in reverse('hello'):
... print(char)
... ol
leh
關於迭代器和生成器的區別,生成器能做到迭代器能做的所有事,而且因為自動建立了__iter__()
和next()
方法,生成器顯得特別簡潔,而且生成器也是高效的。除了建立和儲存程式狀態的自動方法,當發生器終結時,還會自動丟擲stopiteration
異常。乙個帶有yield
的函式就是乙個 生成器,它和普通函式不同,生成乙個 generator 看起來像函式呼叫,但不會執行任何函式**,直到對其呼叫next()
(在 for 迴圈中會自動呼叫next()
)才開始執行。雖然執行流程仍按函式的流程執行,但每執行到乙個yield
語句就會中斷,並返回乙個迭代值,下次執行時從yield
的下乙個語句繼續執行。看起來就好像乙個函式在正常執行的過程中被yield
中斷了數次,每次中斷都會通過yield
返回當前的迭代值(yield
暫停乙個函式,next()
從其暫停處恢復其執行)。
另外對於生成器,python還提供了乙個生成器表示式:類似與乙個yield
值的匿名函式。表示式本身看起來像列表推到, 但不是用方括號而是用圓括號包圍起來:
>>> unique_characters =
>>> gen = (ord(c) for c in unique_characters)
>>> gen
at 0x7f2be4668678>
>>> for i in gen:
... print(i)
...
6979
8377
8278
8968
>>>
如果需要,可以將生成器表示式傳給tuple
、list
或是set
來迭代所有的值並且返回元組、列表或是集合。在這種情況下,不需要一對額外的括號 ———— 直接將生成器表示式ord(c) for c in unique_characters
傳給tuple()
等函式就可以了, python 會推斷出它是乙個生成器表示式。
最後,為什麼要使用生成器?因為效率。使用生成器表示式取代列表解析可以同時節省 cpu 和 記憶體(ram)。如果你構造乙個列表的目的僅僅是傳遞給別的函式,(比如 傳遞給tuple()
或者set())
, 那就用生成器表示式替代吧!
Python迭代器和生成器
先說迭代器,對於string list dict tuple等這類容器物件,使用for迴圈遍歷是很方便的。在後台for語句對容器物件呼叫iter 函式,iter 是python的內建函式。iter 會返回乙個定義了next 方法的迭代器物件,它在容器中逐個訪問容器內元素,next 也是python的...
Python迭代器和生成器
迭代器是訪問集合元素的一種方法 是可以記住遍歷的位置的物件。迭代器物件從集合的第乙個元素開始訪問,直到所有的元素被訪問 他有兩個基本的方法,iter 和next 字串,列表或遠足物件都可以用於建立迭代器 list1 1,2,3,4 it1 iter list1 建立迭代器物件 print next ...
python 迭代器和生成器
迭代器是訪問集合元素的一種方式。迭代器物件從集合的第乙個元素開始訪問,直到所有的元素被訪問完結束。迭代器只能往前不會後退,不過這也沒什麼,因為人們很少在迭代途中往後退。另外,迭代器的一大優點是不要求事先準備好整個迭代過程中所有的元素。迭代器僅僅在迭代到某個元素時才計算該元素,而在這之前或之後,元素可...