日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

怎么确定迭代器后面还有至少两个值_如何理解Python中的可迭代对象、迭代器和生成器

發布時間:2025/3/20 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 怎么确定迭代器后面还有至少两个值_如何理解Python中的可迭代对象、迭代器和生成器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

▍前言

在討論可迭代對象、迭代器和生成器之前,先說明一下迭代器模式(iterator pattern),維基百科這么解釋:

迭代器是一種最簡單也最常見的設計模式。它可以讓用戶透過特定的接口巡訪容器中的每一個元素而不用了解底層的實現。

迭代是數據處理的基石。當內存中放不下數據集時,我們要找到一種惰性獲取數據的方式,即按需一次獲取一個數據項,這就是迭代器模式。▍序列可迭代的原因:iter函數
我們都知道序列是可迭代的。當解釋器需要迭代對象x時,會自動調用iter(x)。
內置的iter函數有以下作用:

  • 檢查對象是否實現了__iter__方法,如果實現了就調用它,獲得一個迭代器。
  • 如果沒有實現__iter__方法,但是實現了__getitem__方法,python會創建一個迭代器,嘗試按順序(從索引0開始)獲取元素。
  • 如果嘗試失敗,python會拋出`TypeError`異常,通常會提示"C object is not iterable",其中C是目標對象所屬的類。

截止到Python3.6,基本上所有的Python序列也都實現了__getitem__方法,這是保證任何序列都可迭代的原因。當然標準的序列也都實現了__iter__方法,之所以對__getitem__也可以創建迭代器是為了向后兼容,未來可能不在這么做。
但是,從Python3.4開始,檢查x能否迭代,最準確的方法是調用iter(x)函數,如果不可迭代,再處理TypeError異常。

▍可迭代對象與迭代器關系

使用iter內置函數可以獲取迭代器對象。也就是說,如果一個對象實現了能返回迭代器的__iter__方法,那么對象就是可迭代的,序列都可以迭代;實現了__getitem__方法,而且其參數是從零開始的索引,這種對象也是可迭代的。

因此可以明確可迭代對象和迭代器之間的關系:Python從可迭代的對象中獲取迭代器。

標準的迭代器接口有兩個方法,即:

  • __next__:返回下一個可用元素,如果沒有元素,拋出StopIteration異常
  • __iter__:返回self,以便在應該使用可迭代對象的地方使用迭代器,比如for循環中。

因為迭代器只需__next__和__iter__兩個方法,所以除了調用next()方法,以及捕獲StopIteration異常之外,沒有辦法檢查是否還有遺留的元素。此外,也沒有辦法還原迭代器。如果想再次迭代,那就要調用iter(…),傳入之前構建迭代器的可迭代對象。

構建可迭代對象和迭代器時經常會出現錯誤,原因是混淆了兩者。要知道,可迭代的對象有個__iter__方法,調用該方法每次都實例化一個新的迭代器;而迭代器要實現__next__方法,返回單個元素,此外還要實現__iter__方法,返回迭代器本身(self),如圖。因此,迭代器可以迭代,但是可迭代的對象不是迭代器。

需要注意的是:

可迭代的對象必須實現__iter__方法,但不能實現__next__方法。另一方面,迭代器應該一直可以迭代,迭代器的__iter__方法應該返回自身。雖然可迭代對象和迭代器都有__iter__方法,但是兩者的功能不一樣,再次強調一下,可迭代對象的__iter__用于實例化一個迭代器對象,而迭代器中的__iter__用于返回迭代器本身,與__next__共同完成迭代器的迭代作用。?

▍生成器?

在Python中創建迭代器最方便的方法是使用生成器。生成器也是迭代器。生成器的語法類似于函數,但是不返回值。為了顯示序列中的每一個元素,會使用yield語句。只要Python函數的定義體中有yield關鍵字,該函數就是生成器函數。調用生成器函數時,會返回一個生成器對象。

獲取生成器通常有兩種方式,生成器函數和生成器表達式。

生成器函數

def gen_123(): # 只要Python代碼中包含yield,該函數就是生成器函數yield 1 #生成器函數的定義體中通常都有循環,不過這不是必要條件;此處重復使用了3次yieldyield 2yield 3 ? if __name__ == '__main__':print(gen_123) # 可以看出gen_123是函數對象# <function gen_123 at 0x10be19>print(gen_123()) # 函數調用時返回的是一個生成器對象# <generator object gen_123 at 0x10be31> ?for i in gen_123(): # 生成器是迭代器,會生成傳給yield關鍵字的表達式的值print(i) # 1# 2# 3 ?g = gen_123() # 為了仔細檢查,把生成器對象賦值給gprint(next(g)) # 1print(next(g)) # 2print(next(g)) # 3print(next(g)) # 生成器函數的定義體執行完畢后,生成器對象會拋出異常。 # Traceback (most recent call last): # File "test.py", line 17, in <module> # print(next(g)) # StopIteration
  • 只要Python代碼中包含yield,該函數就是生成器函數
  • 生成器函數的定義體中通常都有循環,不過這不是必要條件;此處重復使用了3次yield
  • 可以看出gen_123是函數對象
  • 函數調用時返回的是一個生成器對象
  • 生成器是迭代器,會生成傳給yield關鍵字的表達式的值
  • 為了仔細檢查,把生成器對象賦值給g
  • 因為g是迭代器,所以調用next(g)會獲取yield生成的下一個元素
  • 生成器函數的定義體執行完畢后,生成器對象會拋出異常。

生成器表達式

簡單的生成器函數,可以替換成生成器表達式。生成器表達式可以理解為列表推導的惰性版本:不會迫切的構建列表,而是返回一個生成器,按需惰性生成元素。也就是說,如果列表推導是制造工廠的列表,那么生成器表達式就是制造生成器的工廠。如下演示了一個簡單的生成器表達式,并且與列表推導做了對比。

In [1]: def gen_AB(): # 1...: print('start') ...: yield 'A' ...: print('continue')...: yield 'B' ...: print('end.') ...: ? In [2]: res1 = [x*3 for x in gen_AB()] # 2 start continue end. ? In [3]: for i in res1(): # 3...: print('-->', i) ...: AAA BBB ? In [4]: res2 = (x*3 for x in gen_AB()) # 4 ? In [5]: res2 # 5 <generator object <genexpr> at 0x106a07620> ? In [6]: for i in res2(): # 6...: print('-->', i)...: start --> A continue --> B end.
  • #1-創建gen_AB函數
  • #2-列表推到迫切的迭代gen_AB()函數生成的生成器對象產出的元素:’A’和’B’。注意。下面輸出的是start、continue、end.。
  • #3-for循環迭代列表推導生成的res1列表
  • #4-把生成器表達式返回的值賦值給res2。只需調用gen_AB()函數,雖然調用時會返回一個生成器,但是這里并不使用。
  • #5-可以看出res2是一個生成器對象。
  • #6-只有for循環迭代res2時,gen_AB函數的定義體才會真正執行。for循環每次迭代時會隱式調用next(res2),前進到gen_AB函數中的下一個yield語句。注意,gen_AB函數的輸出與for循環中print函數的輸出夾雜在一起。

生成器表達式是創建生成器的簡潔句法,這樣無需定義函數再調用。不過,生成器函數靈活的多,可以使用多個語句實現復雜的邏輯,也可以作為協程(后面有機會講到)使用。遇到簡單的情況時,可以使用生成器表達式,因為這樣掃一眼就知道代碼的作用。其實選擇那種句法很容易判斷:如果生成器表達式需要分行寫,傾向于定義成生成器函數,以便提高可讀性;此外生成器函數有名稱,因此可以重用。

a = (i for i in range(10)) '__next__' in dir(a) # True '__iter__' in dir(a) # True

以上可以看出,生成器也是一種迭代器!

前面我們提到了惰性計算。其實,我們有時候使用生成器而不是傳統的函數時,正是因為惰性計算有好處---只計算需要的數據,并且整個系列不需要一次性全部駐留在內存中。事實上,生成器完全可以有效的生產數值的無限序列,舉一個例子,斐波那契數列是一個經典的無限數字序列,下面用生成器可以產生這個無窮級數:

def fibonacci():a = 0b = 1while True:yield afuture = a + ba = bb = future

以上!

總結

以上是生活随笔為你收集整理的怎么确定迭代器后面还有至少两个值_如何理解Python中的可迭代对象、迭代器和生成器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。