跟你深刻剖析可迭代對象和迭代器的區別與聯繫

導語

可迭代對象和迭代器是常常碰到但又很容易混淆的兩個概念,因此今天小編跟你們深刻剖析一下可迭代對象和迭代器的區別。認真看完本文,你將收穫:python

  • 理解什麼是可迭代對象
  • 理解檢查可迭代對象的方法 
  • 理解什麼是迭代器
  • 可迭代對象和迭代器的關係

事不宜遲,咱們立刻開始吧!函數

可迭代對象

要理解可迭代對象,那首先要搞清楚迭代的概念。關於迭代,維基百科是這樣子定義的:spa

迭代是重複反饋過程的活動,其目的一般是爲了接近併到達所需的目標或結果。每一次對過程的重複被稱爲一次「迭代」,而每一次迭代獲得的結果會被用來做爲下一次迭代的初始值。

從這個定義中,咱們大概能夠知道迭代是對某一個過程的重複。其實在程序中,迭代也是相似的,它是一種遍歷集合元素的方式,請看下面的示例1。code

# 示例1
for i in [1,2,3]:
    print(i)

輸出結果:component

1
2
3

在示例1中,解釋器重複地從列表中取出元素並打印,直到遍歷結束爲止,這就是一個迭代的過程。可見,可迭代對象能夠在for循環中遍歷元素。對象

那什麼樣的對象纔是一個可迭代對象?事實上,只要實現 iter 方法或者實現 __ getitem __方法並且其參數從0開始索引,那麼該對象就是可迭代對象,請看示例2。blog

#示例2
class Vector(object):
    def __init__(self,components):
        self.components = list(components)
        
    def __iter__(self):
        return iter(self.components)

V1 = Vector([1,2,3])
for i in V1:
    print(i)

輸出結果:索引

1
2
3

從示例2中可見,Vector類實現了 __ iter __方法,解釋器能夠從Vector類對象中重複地取出元素並打印。若是要檢查某一個對象是否爲可迭代對象,其實可使用isinstance( )函數,該函數用於判斷對象是否爲某一類型,可是用這個函數判斷不必定準確(緣由後面會說到)。ip

from collections.abc import Iterable
print(isinstance(V1,Iterable))#True

若是咱們只是實現了__ getitem __ ()方法,狀況又會怎麼樣呢?請看示例3。rem

# 示例3
from collections.abc import Iterable
class Vector(object):
    def __init__(self,components):
        self.components = list(components)
    
    def __getitem__(self,index):
        return self.components[index]
    
V1 = Vector([1,2,3])
for i in V1:
    print(i)
print(isinstance(V1,Iterable))

輸出結果:

1
2
3
Flase

從示例3中可看到,Vector實現了__ getitem__方法,解釋器能夠對V1進行迭代並打印元素,可是!使用isinstance()判斷時,返回的結果竟然是False。明明可使用for循環來迭代元素,爲何是判斷是Flase呢?事實上,若是可迭代對象只是實現了__ getitem __ 的話,abc.Iterable是不考慮該方法的,這便致使了isinstance()判斷不許確。更準確的方法應該是調用iter()函數,若是該對象不可迭代,就會拋出TypeError的錯誤。咱們嘗試使用iter()來判斷一下。

# 示例4
print(iter(V1))
#<iterator object at 0x000001B262E35518>

#去掉__getitem__方法後
print(iter(V1))
#TypeError: 'Vector' object is not iterable

從示例4中能夠看到,對於可迭代對象,iter()會返回< iterator object at xxxx >。當去掉__ getitem __ ()方法後再檢查時,便拋出TypeError錯誤。iter()函數用於生成一個迭代器,也就是說能夠返回一個迭代器的就是一個可迭代對象。

該對象之因此能迭代,是由於實現了__iter__()方法。當使用for循環時候,解釋器會檢查對象是否有__ iter__ ()方法,有的話就是調用它來獲取一個迭代器。因此沒有__ iter__ ()方法但實現了__ getitem __ (),解釋器會建立一個迭代器,嘗試從0開始按順序遍歷元素。若是嘗試失敗,Python便會拋出TypeError錯誤。

那麼Python內置類型中究竟有哪些可迭代對象呢?咱們一塊兒盤點一下吧。

  • list
  • dict
  • tuple
  • set
  • string

其實盤點出來的都是序列,因此說任何序列都是可迭代的對象, 其緣由在於他們至少都會實現__ getittem __ 方法(序列均可以經過索引獲取元素)。

迭代器

在介紹可迭代對象時候說到,當使用for循環時候,解釋器會檢查對象是否有__ iter __ ()方法,有的話就是調用它來獲取一個迭代器。那麼究竟什麼是迭代器呢?

其實迭代器是實現了__iter__方法和__next__方法的對象。__ iter__ 方法用於返回迭代器自己,而__ next __ 用於返回下一個元素。咱們自定義一個迭代器,以斐波那契數列爲例說明一下其內部的執行狀況,看示例5。

# 示例5
import itertools
class Fib:
    def __init__(self):
        self.pre = 0
        self.cur = 1

    def __iter__(self):
        return self
    
    def __next__(self):
        p = self.cur
        self.cur += self.pre
        self.pre = p
        return p

f = Fib()
a = list(itertools.islice(f,0,10))
print(a)
#[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

從示例5中__ iter__ ()返回了迭代器對象自己,以便在使用可迭代對象的地方(如for循環中)使用迭代器,而__ next __ ()則經過計算返回下一個元素。咱們再一塊兒看看下面的示例6。

#示例6
>>>s = 'ABCD'
>>>it = iter(s)
>>>while True:print(next(it))
A
B
C
D
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-4-d09d5cde4495> in <module>()
----> 1 while True:print(next(it))

StopIteration:
>>> list(it)
[]
>>>list(iter(s))
['A','B','C','D']

在示例6中先定義一個字符串的可迭代對象,經過iter()函數返回一個迭代器(會自動調用對象的__ iter__ 方法),而後在循環中經過next()取值並打印(會自動調用對象 __ next __()方法),經過next()方法一個個地遍歷可迭代對象中的元素,當遍歷結束,便會拋出StopIteratioin異常,這時迭代器也沒用了,若是要再次迭代,就要使用iter()函數從新構建迭代器。

經過示例5和示例6,咱們可知道迭代器是一個能夠記住遍歷位置的對象,其內部有一個狀態用於記錄迭代所在的位置,以便下次迭代時候能取出正確的元素。迭代器就像一個懶人同樣,當你須要數據時候纔會返回給你,不然就在等待下一次的調用。

若是要檢查某個對象是否爲迭代器,最好的方式是使用isinstance( )函數,見示例7。

# 示例7
from collections.abc import Iterator 
f = Fib()
print(isinstance(f,Iterator)) #True

好了,說了那麼多,究竟迭代器哪些用處呢?其實在Python語言內部,迭代器用於支持:

  • for 循環
  • 構建和擴展集合類型
  • 逐行遍歷文本文件
  • 列表推導、字典推導和集合推導
  • 元組拆包
  • 調用函數時,使用*拆包

可迭代對象和迭代器的關係

  • 可迭代對象不必定是迭代器,迭代器必定是可迭代對象。由於迭代器必定會實現__ iter__方法,而可迭代對象儘管實現了__ iter __ 也不必定實現__next__方法。
  • Python 從可迭代對象中獲取迭代器,根據示例6的例子,咱們知道先是使用iter()函數在迭代對象中獲取迭代器,而後使用next()來獲取下一個元素,關係以下圖所示。

總結

  • 可迭代對象實現了__iter__ 方法或者實現 __ getitem__方法並且其參數從0開始索引。
  • 使用iter()函數判斷可迭代對象更準確
  • 任何序列都是可迭代對象
  • 迭代器對象實現了__ iter __和__next __方法。
  • 迭代器是一個能夠記住遍歷位置的對象,其內部有一個狀態用於記錄迭代所在的位置,以便下次迭代時候能取出正確的元素
  • 檢查對象是否爲迭代器最好的方式是調用isinstance()方法。

以上就是小編今天跟你們分享的內容了,若是有什麼疑問記得聯繫小編哦~

公衆號:CVpython,專一於分享Python和計算機視覺,咱們堅持原創,不按期更新,但願文章對你有幫助,快點掃碼關注吧。

相關文章
相關標籤/搜索