天天看點

疊代器、生成器和yield的知識總結(非原創、歸納總結各類資料)一、什麼是疊代器二、建立疊代器三、疊代器的使用

環境說明: python3.7

通過查閱各類資料,總結一下疊代器相關知識,作為資料留存,友善以後查閱溫習。

一、什麼是疊代器

疊代器是實作了__next__()方法的對象(這個方法在調用時不需要任何參數),它是通路可疊代序列的一種方式,通常其從序列的第一個元素開始通路,直到所有的元素都被通路才結束。 [注意]:疊代器隻能前進不能後退

[疊代器的優點]:

使用疊代器不要求事先準備好整個疊代過程中的所有元素。疊代器僅僅在疊代到某個元素時才計算該元素,而在這之前或之後元素可以不存在或者被銷毀。是以疊代器适合周遊一些數量巨大甚至無限的序列。

以python2.x中的range函數和xrange函數為例,range函數傳回的是清單,xrange函數傳回的是疊代器,是以range函數占用的記憶體空間比xrange大,是以,在python3.x中,改進range函數傳回疊代器,取消xrange函數。

二、建立疊代器

(一)使用iter(iterable)可将可疊代序列轉換為疊代器

a=[1,2,3,4]
b=(1,2,3)
str='Tomwenxing'
print(iter(a))
print(iter(b))
print(iter(str))
           

輸出如下:

<list_iterator object …>

<tuple_iterator object …>

<str_iterator object …>

說明: 并不是所有的資料類型/結構都能轉換為疊代器,清單、元組、字元串等本身就是iterable,是以可以通過iter函數生成疊代器。

(二)自定義支援iterable的類

與上面“說明”一緻,如果我們定義了一個支援iterable的類,那麼我們也可以使用iter函數生成對應的疊代器。

Python中疊代器的本質,每次調用__next__()方法都傳回下一個元素或抛出StopIteration的容器對象

由于Python中沒有“疊代器”這個類,是以具有以下兩個特性的類都可以稱為“疊代器”類:

1、有__next__()方法,傳回容器的下一個元素或抛出StopIteration異常

2、有__iter__()方法,傳回疊代器本身

如下例所示,通過在Fib類中定義上述兩個函數,就可以認為Fib是支援iterable。

class Fib(object):

    def __init__(self,length):
        self.length=length
        self.curLength,self.preNum,self.curNum=0,0,1

    def __iter__(self):
        return self

    def __next__(self):
        if self.curLength<self.length:
            r=self.curNum
            self.preNum,self.curNum=self.curNum,self.preNum+self.curNum
            self.curLength=self.curLength+1
            return r
        raise StopIteration()

if __name__=="__main__":
    length=5
    for n in Fib(length):
        print(n)
           

輸出如下:

1

1

2

3

5

(三)生成器可看成是一個疊代器

在 Python 中,使用了 yield 的函數被稱為生成器(generator)。

yield 的作用就是把一個函數變成一個 generator,帶有 yield 的函數不再是一個普通函數,Python 解釋器會将其視為一個 generator,調用該函數不會執行,而是傳回一個生成器對象(generator 對象)。生成器對象可看成是一個疊代器對象,使用方法一樣。

在調用生成器運作的過程中,每次遇到 yield 時函數會暫停并儲存目前所有的運作資訊,傳回 yield 的值, 并在下一次執行 next() 方法時從目前位置繼續運作。

#!/usr/bin/python3
 
import sys
 
def fibonacci(n): # 生成器 - 斐波那契
    a, b, counter = 0, 1, 0
    while True:
        if (counter > n): 
            return
        yield a
        a, b = b, a + b
        counter += 1
if __name__ == '__main__':
    f = fibonacci(10)  # f 是一個生成器,可看成是一個疊代器。
    print(type(f))
           

輸出如下:

<class ‘generator’>

三、疊代器的使用

(一)使用next函數疊代

例1:

a=[1,2,3,4]
it=iter(a)
print(next(it))
print(next(it))
           

例2:

class Fib(object):

    def __init__(self,length):
        self.length=length
        self.curLength,self.preNum,self.curNum=0,0,1

    def __iter__(self):
        return self

    def __next__(self):
        if self.curLength<self.length:
            r=self.curNum
            self.preNum,self.curNum=self.curNum,self.preNum+self.curNum
            self.curLength=self.curLength+1
            return r
        raise StopIteration()

if __name__=="__main__":
	fib=Fib(5)
	print(next(fib))
	
	it=iter(fib)
	print(next(it))
           

特别說明: 通過上述案例,總結:Fib類的對象可直接被next函數調用疊代,Fib類的對象轉換成疊代器後也可被next函數調用疊代。疑問:與可疊代序列類比,Fib類對象不是應該轉換成疊代器後才可被next函數調用嗎,為什麼可直接被next函數調用?什麼原理,怎麼個過程啊,請大神指教!

例3:

#!/usr/bin/python3

import sys


def fibonacci(n):  # 生成器函數 - 斐波那契
    a, b, counter = 0, 1, 0
    while True:
        if (counter > n):
            return
        yield a
        a, b = b, a + b
        counter += 1


if __name__ == '__main__':
    f = fibonacci(10)  # f 是一個生成器,可看成是一個疊代器。
    print(type(f))
    print(next(f))
           

(二)使用for循環疊代

如下例:

#!/usr/bin/python3

import sys


def fibonacci(n):  # 生成器函數 - 斐波那契
    a, b, counter = 0, 1, 0
    while True:
        if (counter > n):
            return
        yield a
        a, b = b, a + b
        counter += 1


if __name__ == '__main__':
    f = fibonacci(10)  # f 是一個生成器,可看成是一個疊代器。
    print(type(f))
    for num in f:
        print(num)
           

特别說明: 在執行for循環時,每執行一次,暗含會調用一次next函數。