Python難點解析---初級篇3.迭代(可迭代、迭代器、生成器)

什麼是迭代

Wiki定義:是重複反饋過程的活動,其目的是爲了接近併到達所需的目標或結果。

在程序中,迭代是一種遍歷集合元素的方式,我們可以通過索引值遞增來遍歷集合元素,而迭代是遍歷集合元素另一種方式。

下面是使用索引來進行遍歷集合元素的方式:

val = [1,2,3,4,5]
for i in range(len(val)):
    retVal = val[i]

這種方式在C++中很常見,在Python中我們可以用更簡潔的語法來進行遍歷,也就是迭代

#三個關鍵字
說到迭代,在Python裏就會提到下面三個關鍵詞:

  • Iterable(可迭代)
  • iterator(迭代器)
  • generator(生成器)

這三個關鍵字,可能從一開始的某段代碼你就接觸到了,只是你沒有發覺,代碼是這樣的。

val = [1,2,3,4,5]
for i in val:
    print i

上面這個for...in,就是Python中迭代器的語法糖。好了,現在你可能開始在想這個for做了什麼事了,先把這個疑問放在心裏,我們先一步步來解析上面的幾個關鍵字。

Iterable 可迭代

先來看個反面教材,如果我們用for...in語法糖去遍歷一個int會怎樣???

intVal = 1024
for _ in intVal:
    pass

>>>TypeError: 'int' object is not iterable

從上面的錯誤可以看到,整數類型的對象不是可迭代的,也就是說for..in只適用於iterable對象,那麼什麼類型的對象纔是**iterable(可迭代)**呢。

在Python中,實現了__iter__函數的類型都是可迭代的,例如list,tuple,dict等

可以用dir函數查看一下是否存在協議函數__iter__

print '__iter__' in dir(dict)
print '__iter__' in dir(list)
print '__iter__' in dir(tuple)

>>>True                                                                                                                                                                                                                                   
>>>True                                                                                                                                                                                                                                   
>>>True 

通過上面的方式我們可以判斷一個對象是不是可迭代的,當然我們還有另外一種更接地氣的方法。

l = [1]
from collections import Iterable
print isinstance(l, Iterable)  #注意這裏只能用實例進行判斷,而不能用list判斷

iterator 迭代器

對於一個可迭代的對象,我們需要藉助迭代器來對其進行迭代,那麼我們怎麼才能得到一個迭代器呢?

iter()方法

通過使用iter方法,我們可以得到一個迭代器,記住,要傳入一個可迭代對象做爲參數:

l = [1]
o = iter(l)
print type(o)
>>><type 'listiterator'>

從上面的代碼可以看到,我們通過將一個可迭代對象傳給iter方法得到了一個迭代器,那麼有了這個迭代器之後,我們應該怎麼迭代呢?

next()方法

調用迭代器next方法可以對元素進行遍歷,但是next方法是不能無限使用的:

l = [1, 2, 3]
o = iter(l)
print o.next()
print o.next()
print o.next()
print o.next()

>>>1                                                                                                                                                                                                                                      
>>>2                                                                                                                                                                                                                                      
>>>3                                                                                                                                                                                                                                      
>>>Traceback (most recent call last):                                                                                                                                                                                                     
  File "e:\Microsoft VS Code\TestFiles\test.py", line 63, in <module>                                                                                                                                                                  
    print o.next()                                                                                                                                                                                                                     
StopIteration  

通過next方法我們可以一個個的遍歷可迭代對象中的元素,當遍歷結束的時候,會引發異常StopIteration


迭代器類

除了以上的方法,我們還可以構造一個類來進行迭代,這個類需要實現next__iter__方法,下面構造了一個斐波那契數列:

class FabIteratorClass(object):
    def __init__(self, max):
        self.m_Max = max
        self.m_Idx = 0
        self.m_a = 0
        self.m_b = 1

    def __iter__(self):
        return self

    def next(self):
        if self.m_Idx < self.m_Max:
            ret = self.m_b
            self.m_a, self.m_b = self.m_b, self.m_a + self.m_b
            self.m_Idx += 1
            return ret
        raise StopIteration()

for val in FabIteratorClass(3):
    print val

>>>1
>>>1
>>>2

所以,作爲一個迭代器,他的特徵如下:

  • 擁有__iter__方法,或者由iter方法返回
  • 擁有next方法
  • 會產生StopIteration異常

生成器

說到生成器,那麼一定會說到一個關鍵字yield,只要一個函數裏出現了這個關鍵字,我們就把這個函數稱爲生成器,生成器是一種***內存友好***的函數,例如平時用到的xrange函數,就是一個生成器,生成器不會把所有值預先生成,而是在需要時才生成,是一種Lazy Evaluation的做法。生成器也是迭代器的一種!

同樣是斐波那契數列,我們用生成器處理一下:

def fab(max):
    idx = 0
    a = 0
    b = 1
    while idx < max:
        ret = b
        a, b = b, a + b
        idx += 1
        yield ret

c = fab(5)
print type(c)
for val in c:
    print val
>>><type 'generator'> 
>>>1                                                                                                                                                                                                                                      
>>>1                                                                                                                                                                                                                                      
>>>2                                                                                                                                                                                                                                      
>>>3                                                                                                                                                                                                                                      
>>>5 

總結:

  • 三者的繼承關係是這樣:generator—>Iterator—>Iterable
  • 迭代器類型需要實現__iter__next方法,生成器是一種特殊的迭代器,內部支持了生成器協議,不需要明確定義__iter__()和next()方法
  • 迭代器一定是可迭代對象,但是可迭代對象不一定是迭代器
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章