2021-12-25 Python-20

初學(xué)時(shí),被可迭代對象,迭代器和生成器繞的云里霧里。
首先來區(qū)分一下這幾個(gè)概念。

迭代器(iterator)

迭代器是指內(nèi)部包含了 iternext 方法的類。
iter 函數(shù)返回對象本身,而 next 方法則是返回下一個(gè)元素。

#依次輸出迭代器中的元素
class An_Iterator(object):
    def __init__(self,data):
        self.data=data
        self.index=0
    def __iter__(self):
        return self
    def __next__(self):
        if self.index == len(self.data):
            raise StopIteration
        value=self.data[self.index]
        self.index += 1
        return value

string=An_Iterator('abc')
next(string)  #也可以寫作 string.__next__() 得到元素 'a'
next(string)  # 'b'
next(string)  # 'c'
next(string)  # 拋出異常 StopIteration

在上面的代碼塊中,先創(chuàng)建了 An_Iterator 的類,內(nèi)部有個(gè)iter的方法,返回對象本身。當(dāng)訪問內(nèi)部的next方法時(shí),返回下一個(gè)元素。當(dāng)超出了范圍后,返回異常。
實(shí)際上滿足下面兩個(gè)條件的都可以稱為迭代器
(1)iter() 方法返回迭代器對象本身。
(2)next() 方法會(huì)返回下一個(gè)迭代器對象。如果數(shù)據(jù)沒有了,拋出 StopIteration 異常。

for i in string:
    print(i)

一般不用next方法來返回,可以用 for 循環(huán)來遍歷循環(huán)。在 for 語句的幕后,其實(shí) python 先對對象調(diào)用了 iter 函數(shù)。這個(gè)函數(shù)返回了迭代器對象,這邊也就是返回了本身。返回的對象能夠使用 next 方法,調(diào)用下一個(gè)元素。

生成器(generator)

生成器是一種特殊的迭代器,也含有iternext方法。

生成器的構(gòu)造

生成器可以通過2種方法進(jìn)行構(gòu)造。
(1) 將函數(shù)定義中的 return 變成 yield,即可定義一個(gè)生成器
每次語句執(zhí)行到 yield 時(shí),就跳出了定義的函數(shù)。下一次再執(zhí)行,則從上次中斷的地方繼續(xù)執(zhí)行。所以在迭代生成器時(shí),每一次執(zhí)行都可以保留上一次的狀態(tài),而不是像普通方法那樣,遇到 return 就返回結(jié)果,下一次執(zhí)行只能再次重復(fù)上一次的流程。

def squares(n=10):
'''返回1:n^2'''
    for i in range(1,n+1):
        yield i**2

a=squares(3) #此處并未執(zhí)行squares中的代碼,只是創(chuàng)建了一個(gè)生成器對象
next(a) #1
next(a) #4
next(a) #9

for element in a:
    print(element,end=' ')
#1 4 9

再看下一個(gè)例子,更深入理解 yield 的用法。

def counter_generator(low, high):
    while low <= high:
       yield low
       low += 1

for i in counter_generator(5,10): 
    print(i, end=' ')

# 5 6 7 8 9 10

在 while 循環(huán)中,當(dāng)它到達(dá) yield 語句時(shí),將返回 low 值,并退出生成器。在第二次下一次調(diào)用期間,發(fā)生器在之前中斷的地方恢復(fù),然后low+1。再繼續(xù)使用 while 循環(huán),并再次進(jìn)入 yield 語句。

之前提到生成器和迭代器都有iternext方法,可以通過dir() 函數(shù)查看。

dir(string)
dir(a)
#能在輸出的列表中找到__iter__和__next__方法

生成器最大的好處就是能夠處理很大的數(shù)據(jù)而不占用很大內(nèi)存, 因?yàn)樗且贿呌?jì)算一邊生成元素的,而不是一下子把所有的元素都導(dǎo)入到內(nèi)存中,所以大大節(jié)省了內(nèi)存,理論上可以產(chǎn)生包含無限元素的生成器。
(2)生成器表達(dá)式
在列表表達(dá)式中,以中括號(hào)的形式來創(chuàng)建,生成器表達(dá)式只要把中括號(hào)替換成小括號(hào)即可。

gen=(x**2 for x in range(10))
for i in gen:
    print(i)

生成器有一個(gè)問題就是不能重復(fù)使用,當(dāng)執(zhí)行完上面的代碼后,再執(zhí)行依次,不會(huì)有內(nèi)容輸出。

可迭代對象(Iterable)

可迭代對象有iter方法,能夠返回一個(gè)迭代器。

#還是上面這樣一個(gè)迭代器
class An_Iterator(object):
    def __init__(self,data):
        self.data=data
        self.index=0
    def __iter__(self):
        return self
    def __next__(self):
        if self.index == len(self.data):
            raise StopIteration
        value=self.data[self.index]
        self.index += 1
        return value
class It(object):
    def __init__(self,data):
        self.data=data
    def __iter__(self):
        return An_Iterator(self.data)

b=It('abcd') #b是一個(gè)可迭代對象
dir(b) #輸出中,b包含了__iter__,而沒有__next__方法   

上述的代碼中,定義了一個(gè) An_Iterator 的迭代器,定義了 It 類,這個(gè)類包含了iter方法,并且返回了迭代器An__Iterator,符合可迭代的對應(yīng),b是 It 的一個(gè)實(shí)例化, 所以b是可迭代對象。
在 python 的數(shù)據(jù)結(jié)構(gòu)中,字符串,tuple,list,dict,set均為可迭代對象,而文件對象是迭代器對象。
對可迭代對象,也可以通過for循環(huán)遍歷,但是不能使用next方法
因?yàn)?for 語句執(zhí)行過程中,先將對象使用iter方法,這時(shí)候就返回一個(gè)迭代器,而迭代器自然可以用next方法。

判斷迭代器和可迭代對象

from collections.abc import Iterable,Iterator
list_1=[1,2,3]
isinstance(list_1,Iterable) #True
isinstance(list_1,Iteration) #False

從上面的結(jié)果也可以看到,列表是可迭代對象,而不是迭代器。

參考:
15分鐘徹底搞懂迭代器、可迭代對象、生成器【python迭代器】_嗶哩嗶哩_bilibili

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容