1. 程式人生 > >Python之容器、叠代器、生成器

Python之容器、叠代器、生成器

模式 tro 斐波那契數 並保存 oop absolute 部分 iteration 訪問

1.容器、可叠代對象、叠代器、生成器概念

1. 容器:存儲許多元素的數據結構。通常存儲在內存(叠代器、生成器是特例)可以使用in來判斷某個元素是否在存在的對象都是容器

舉個例子:容器就像一個箱子,裏面可以存放許多東西,我可以往這個箱子存取東西,可以判斷這個箱子是否有某樣東西

2.可叠代對象:可以使用iter()變成叠代器的對象都是可叠代對象,大部分容器都是可叠代對象(str,set,list,tuple,打開狀態的files,sockets等等)

3.叠代器:它是一個帶狀態的對象,保存當前記錄狀態,當使用next()函數調用時,可以返回容器的下一個值。如果容器中沒有更多元素了,則拋出StopIteration異常.

任何實現了__iter__() and next()方法的對象都是叠代器,__iter__返回叠代器自身,__next__對象返回下一個值。生成器是另一種形態的叠代器

叠代器就是實現了工廠模式的對象,它在你每次你詢問要下一個值的時候給你返回。比如itertools函數返回的都是叠代器對象。

4.生成器:使用yield關鍵字,python都會把這個函數視為一個生成器.它返回了一個可叠代的對象,可以使用next()訪問它裏面的值了

5.如何使用叠代器呢?

1.方式是使用for 。。 in 。語法糖結構來遍歷叠代器。
for默認的會調用__iter__返回一個叠代對象,然後調用next()方法調用叠代對象的__next__方法獲取下一個值。
如果最後沒有值了,叠代器會拋出一個異常,for會捕捉處理這個異常,退出循環.

2.先獲取叠代器對象,如使用it = iter(list)方法,在調用next(it)獲取下一個值。最後沒值了會拋出異常(StopIteration)

下面一張圖來說明他們之間的關系

技術分享圖片

2.具體實例來演示上面的內容

以斐波那契數列來舉例

1.普通的函數實現

# 普通函數斐波那契數列
def fib1(n):
    pre, cur = 0, 1
    i = 0
    while i < n:
        print(cur, end=‘ ‘)
        pre, cur = cur, cur + pre
        i += 1

調用: fib1(10)
輸出:1 1 2 3 5 8 13 21 34 55

2.普通的函數實現改進

# 普通函數斐波那契數列改進
def fib1(n):
    result = []
    pre, cur = 0, 1
    i = 0
    while i < n:
        result.append(cur)
        pre, cur = cur, cur + pre
        i += 1
    return result
    
調用:lst = fib1(10)
      print(lst)
輸出:[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

3.自定義一個可叠代的類來實現斐波那契數列

class Fib:

    def __init__(self, stop):
        self.stop = stop
        self.pre = 0
        self.cur = 1
        self.start = 0
        print(‘init finish‘)

    def __iter__(self):
        print(‘return iter‘)
        return self

    def __next__(self):
        print(‘return next value‘)
        if self.start < self.stop:
            self.start += 1
            x = self.cur
            self.pre, self.cur = self.cur, self.cur + self.pre
            return x
        else:
            raise StopIteration()

初始化類,得到一個類實例對象f,可以看到"init finish"打印出來了
In [1]: f = Fib(10)
Out[1]:init finish

我們知道一個可叠代對象可以通過iter()函數轉換成一個叠代器,
從下面的調用我們可以看出,當我們使用iter()函數時,它默認去調用函數的__iter__()函數,返回叠代對象
In [2]: it = iter(f)
Out[2]:return iter

當我們獲取了叠代對象,我們調用next()函數來獲取我們想要的值,
那麽next()有做了哪些動作呢
1.它調用類中的__next__()方法
2.我們__next__()方法,返回當前值,並保存當前值記錄狀態和算出下一次調用要返回的值
In [3]: next(it)
Out[30]:return next value
Out[30]: 1

In [3]: next(it)
Out[30]:return next value
Out[30]: 2

如果一直執行next(),它會一直返回值,直到拋出StopIteration()異常

4.使用生成器

使用生成器,我們有兩種形式:
1.創建生成器函數,使用yield關鍵字
2.使用生成器表達式

4.1創建生成器函數

# 使用yield實現斐波那契數列
def fib(n):
    pre, cur = 0, 1
    i = 0
    while i < n:
        print(‘call this‘)
        yield cur
        pre, cur = cur, pre + cur
        i += 1
        print(‘here‘)

從下面的執行結果我們可以看出,使用關鍵字yield後,調用fib(10)它的返回值是一個生成器
In [33]: f = fib(10)
In [34]: type(f)
Out[34]: generator

從上面圖我們知道generator is iterator,我們可以使用next()函數獲取值,可以看出我們沒執行一次next(),
好像我們的程序就在yield返回cur,然後停到這不執行,直到下次調用next()函數又繼續往下走,不停重復這個過程
In [1]: next(f)
call this
Out[1]: 1

In [2]: next(f)
here
call this
Out[2]: 2

In [3]: next(f)
here
call this
Out[3]: 3

4.2生成器表達式實現斐波那契數列

# 從下面我們可以看出,使用()後a是一個generator類型
In [1]: a = ( x for x in fib3(10))
In [2]: type(a)
Out[2]: generator

In [3]: next(a)
call this
Out[3]: 1

In [4]: next(a)
here
call this
Out[4]: 1

In [5]: next(a)
here
call this
Out[5]: 2

5.對於可叠代對象遍歷,我們一定會想到for循環

下面具體解釋下for循環:

1.for循環的一般格式如下:
for iter_var in iterable:
    suite_to_repeat
從上面可以看出,只要是可叠代對象都可以使用
它的裏面到底做了些什麽呢?

舉個例子吧,我們看看for循環它到底做了哪些工作

class Fib:

    def __init__(self, stop):
        self.stop = stop
        self.pre = 0
        self.cur = 1
        self.start = 0
        print(‘init finish‘)

    def __iter__(self):
        print(‘return iter‘)
        return self

    def __next__(self):
        print(‘return next value‘)
        if self.start < self.stop:
            self.start += 1
            x = self.cur
            self.pre, self.cur = self.cur, self.cur + self.pre
            return x
        else:
            raise StopIteration()
           
對一個可叠代對象進行叠代操作
def fortest():
    for x in Fib(4):
        print(x)

fortest()


import dis
dis.dis(fortest)

打印以下信息:
init finish
return iter
return next value
1
return next value
1
return next value
2
return next value
3
反編譯結果
108           0 SETUP_LOOP              24 (to 26)
              2 LOAD_GLOBAL              0 (Fib)
              4 LOAD_CONST               1 (4)
              6 CALL_FUNCTION            1
              8 GET_ITER
        >>   10 FOR_ITER                12 (to 24)
             12 STORE_FAST               0 (x)

109          14 LOAD_GLOBAL              1 (print)
             16 LOAD_FAST                0 (x)
             18 CALL_FUNCTION            1
             20 POP_TOP
             22 JUMP_ABSOLUTE           10
        >>   24 POP_BLOCK
        >>   26 LOAD_CONST               0 (None)
             28 RETURN_VALUE

可以看出在for內部有兩個很重要的指令GET_ITER,FOR_ITER,
GET_ITER相當於調用iter(Fib(4),返回對象叠代器it
FOR_ITER相當於調用next(it),調用類內部的__next()__()方法獲取值,一直循環這個過程,直到遇到拋出的StopIteration()異常

Python之容器、叠代器、生成器