溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Python迭代器生成器

發(fā)布時間:2020-07-07 03:36:58 來源:網(wǎng)絡(luò) 閱讀:180 作者:liangruifeng 欄目:開發(fā)技術(shù)

  在學(xué)習(xí)python數(shù)據(jù)結(jié)構(gòu)的過程中,可迭代對象,迭代器,生成器這些概念參雜在一起,難免讓初學(xué)者一頭霧水,今天就來捋捋這些概覽。

可迭代對象(iterable)

  什么是可迭代對象,通俗的講就是可以直接通過for循環(huán)遍歷的對象就可稱為可迭代對象Iterable,可以使用isinstance()判斷一個對象是否是Iterable對象:

>>>from collections import Iterable
>>>isinstance([], Iterable)
True
>>>isinstance({}, Iterable)
True
>>>isinstance('123', Iterable)
True
>>>isinstance(123, Iterable)
False

可迭代對象并不指某種具體的數(shù)據(jù)類型,list, dict, set, str都是迭代對象,再比如打開狀態(tài)的files,sockets也是可迭代對象,可迭代對象是指代對象的一種屬性,代表該對象是可迭代的??傻鷮ο髮?shí)現(xiàn)了__iter__方法,該方法返回一個迭代器對象。

迭代器(iterator)

  任何實(shí)現(xiàn)了__iter__和__next__方法的對象都是迭代器(python2是實(shí)現(xiàn)__iter__和next方法),__iter__返回迭代器自身,__next__返回容器中的下一個值,如果容器中沒有更多元素了,則拋出StopIteration異常??梢允褂胕sinstance()判斷一個對象是否是Iterator對象:

>>>from collections import Iterator
>>>isinstance([], Iterator)
False
>>>isinstance({}, Iterator)
False
>>>isinstance('123', Iterator)
False
>>>isinstance((x for x in range(10)), Iterator)
True

其中(x for x in range(10))是生成器表達(dá)式,它返回的是一個生成器對象,不同于列表生成式[x for x in range(10)]返回一個list對象。生成器對象都是迭代器對象,但list, dict, str雖然是可迭代對象,但不是迭代器對象,可以使用iter()將list, dict, str等可迭代對象變成迭代器對象。

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

python的迭代器對象表示一個數(shù)據(jù)流,可以將這個數(shù)據(jù)流看作一個有序序列,但我們并不知道序列的長度,只能不斷通過調(diào)用next()函數(shù)實(shí)現(xiàn)按需計(jì)算下一個數(shù)據(jù),因此迭代器的計(jì)算是惰性的,只有在需要返回下一個數(shù)據(jù)時它才計(jì)算,迭代器的這種特性可以大大減少內(nèi)存的開銷,迭代器對象甚至可以表示一個無限大的數(shù)據(jù)流,而讓list, dict或者str存儲一個無限大的數(shù)據(jù)流是不可能的。

下面我們通過迭代器來實(shí)現(xiàn)斐波那契數(shù)列:

from collections import Iterable
from collections import Iterator

class Fib:
    def __init__(self, max):
        self.n, self.max = 0, max
        self.a, self.b = 0, 1

    def __iter__(self):
        return self

    def __next__(self):
        if self.n < self.max:
            self.n += 1
            self.a, self.b = self.b, self.a + self.b
            return self.a
        else:
            raise StopIteration

if __name__ == '__main__':
    fib = Fib(10)
    print(isinstance(fib, Iterable)) # True
    print(isinstance(fib, Iterator)) # True
    print([e for e in fib]) # [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

  Fib既是一個可迭代對象(因?yàn)樗鼘?shí)現(xiàn)了__iter__方法),又是一個迭代器(因?yàn)閷?shí)現(xiàn)了__next__方法)。實(shí)例變量a和b用于維護(hù)迭代器內(nèi)部的狀態(tài)。每次調(diào)用next()方法的時候做兩件事:
為下一次調(diào)用next()方法修改狀態(tài),為當(dāng)前這次調(diào)用生成返回結(jié)果。

迭代器就像一個懶加載的工廠,等到有人需要的時候才給它生成值返回,沒調(diào)用的時候就處于休眠狀態(tài)等待下一次調(diào)用。

生成器(generator)

  生成器是一種特殊的迭代器,不過這種迭代器更加優(yōu)雅。它不需要再像上面的類一樣寫__iter__()和__next__()方法了,只需要一個yiled關(guān)鍵字。

用生成器來實(shí)現(xiàn)斐波那契數(shù)列的例子是:

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        n = n + 1
        a, b = b, b + a
        yield a

f = fib(10)
print(f) # <generator object fib at 0x10d8cf888>
print([e for e in f])   # [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

fib函數(shù)中的yield關(guān)鍵字,將該函數(shù)變成了一個生成器,當(dāng)執(zhí)行f=fib(10)返回的是一個生成器對象,此時函數(shù)中的代碼并不會執(zhí)行,只有顯示或隱示地調(diào)用next的時候才會真正執(zhí)行里面的代碼,在每次調(diào)用next()方法時,遇到y(tǒng)ield語句返回值并中斷,再次執(zhí)行時從上次返回的yield語句處繼續(xù)執(zhí)行。
生成器是python非常強(qiáng)大的特性,相比其他容器對象它更加節(jié)省內(nèi)存,同時使用更少的代碼,使你的代碼更加的優(yōu)雅,凡事以下結(jié)構(gòu)都可以通過生成器重構(gòu):

def fun():
    result = []
    for ... in ...:
        result.append(x)
    return result

def fun_gen():
    for ... in ...:
        yield x
總結(jié)
  1. 可迭代對象實(shí)現(xiàn)了__iter__方法,該方法返回一個迭代器對象。
  2. 迭代器持有一個內(nèi)部狀態(tài)的字段,用于記錄下次迭代返回值,它實(shí)現(xiàn)了__next__和__iter__方法,迭代器不會一次性把所有元素加載到內(nèi)存,而是需要的時候才生成返回結(jié)果。
  3. 生成器是一種特殊的迭代器,它的返回值不是通過return而是用yield。
向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI