迭代器和生成器總結

迭代器:python


是一個抽象的概念,任何對象,若是它的類有 next 方法和 iter 方法返回本身自己,對於 string、list、dict、tuple 等這類容器對象,使用 for 循環遍歷是很方便的。在後臺 for 語句對容器對象調用 iter()函數,iter()是 python 的內置函數。iter()會返回一個定義了 next()方法的迭代器對象,它在容器中逐個訪問容器內元素,next()也是 python 的內置函數。在沒有後續元素時,next()會拋出一個 StopIteration 異常。函數


關於iter()和next():工具


一、iter(iterable)函數是把可迭代對象的迭代器取出來,內部是調用可迭代對象的__iter__方法,來取得迭代器的
二、next(iterator)函數是經過迭代器取得下一個位置的值,內部是調用迭代器對象的__next__方法,來取得下一個位置的值
注意: 
當咱們已經迭代完最後一個數據以後,再次調用next()函數會拋出StopIteration的異常,來告訴咱們全部數據都已迭代完成,不用再執行next()函數了。
因此:
咱們要想構造一個迭代器,就要實現它的__next__方法。但這還不夠,python要求迭代器自己也是可迭代的,因此咱們還要爲迭代器實現__iter__方法,而__iter__方法要返回一個迭代器,迭代器自身正是一個迭代器,因此迭代器的__iter__方法返回自身便可。
結論: 
一個實現了__iter__方法和__next__方法的對象,就是迭代器,迭代器同時也是一個可迭代對象spa


示例代碼:code

class FibIterator(object):
    """斐波那契數列迭代器"""

    def __init__(self, n):
        # 記錄生成fibonacci的數列的個數
        self.n = n
        # 記錄當前遍歷的下標
        self.current_index = 0
        # 記錄fibonacci數列前面的兩個值
        self.num1 = 0
        self.num2 = 1

    def __next__(self):
        """被next()函數調用來獲取下一個數"""
        if self.current_index < self.n:
            num = self.num1
            self.num1, self.num2 = self.num2, self.num1 + self.num2
            self.current_index += 1
            return num
        else:
            raise StopIteration

    def __iter__(self):
        """迭代器的__iter__返回自身便可"""
        return self


if __name__ == '__main__':
    fib = FibIterator(10)
    for num in fib:
        print("  ", num, end="")

# 運行結果: 0 1 1 2 3 5 8 13 21 34

 

生成器(Generator):對象


是建立迭代器的簡單而強大的工具。生成器是一種特殊的迭代器,它比迭代器寫起來更加優雅,它們寫起來就像是正規的函數,只是在須要返回數據的時候使用 yield 語句。每次 next()被調用時,生成器會返回它脫離的位置(它記憶語句最後一次執行的位置和全部的數據值)blog

 

最簡單的生成器就是把一個列表生成式的[ ]改爲( )
例如:g = (x*2 for x in rang(5)),就是一個生成器
另一種生成器的建立方法就是這一個函數裏面加yield:
例如把上面的斐波那契函數改寫成生成式以下:內存

def fib(n):
    current_index = 0
    num1, num2 = 0, 1
    while current_index < n:
        # print(num1) # 打印斐波那契數列
        """
         1. 假如函數中有yield,則再也不是函數,而是生成器
         2. yield 會產生一個斷點
         3. 假如yield後面緊接着一個數據,就會把數據返回,
            做爲next()函數或者for ...in...迭代出的下一個值
        """
        yield num1
        num1, num2 = num2, num1 + num2
        current_index += 1

if __name__ == '__main__':
    # 假如函數中有yield,則再也不是函數,而是一個生成器
    gen = fib(10)

    #  生成器是一種特殊的迭代器
    for num in gen:
        print(num)

# 運行結果: 0 1 1 2 3 5 8 13 21 34

經過代碼能夠很直觀看出生成器更優雅更省代碼ci

yield其實就是保存當前程序執行狀態。你用 for 循環的時候,每次取一個元素的時候就會計算一次。用 yield 的函數叫 generator,和 iterator 同樣,它的好處是不用一次計算全部元素,而是用一次算一次,能夠節省不少空間。generator每次計算須要上一次計算結果,因此用 yield,不然一 return,上次計算結果就沒了,簡單來講一個函數裏面加了yield就是生成器。
還有咱們除了可使用next()函數來喚醒生成器繼續執行外,還可使用send()函數來喚醒執行。使用send()函數的一個好處是能夠在喚醒的同時向斷點處傳入一個附加數據。generator

總結:


一、使用了yield關鍵字的函數再也不是函數,而是生成器。(使用了yield的函數就是生成器)
二、yield關鍵字有兩點做用:
 保存當前運行狀態(斷點),而後暫停執行,即將生成器(函數)掛起
 將yield關鍵字後面表達式的值做爲返回值返回,此時能夠理解爲起到了return的做用
三、可使用next()函數讓生成器從斷點處繼續執行,即喚醒生成器(函數)

 

區別:


生成器能作到迭代器能作的全部事,並且由於自動建立了 iter()和 next()方法,生成器顯得特別簡潔,並且生成器也是高效的,使用生成器表達式取代列表解析能夠同時節省內存。除了建立和保存程序狀態的自動方法,當發生器終結時,還會自動拋出 StopIteration 異常。

相關文章
相關標籤/搜索