Python系列5——迭代對象、迭代器、生成器

目錄

 

1 可迭代對象

1.1什麼是可迭代對象、如何判斷是否是可迭代對象

2 迭代器

3 for循環的本質

4 生成器


1 可迭代對象

1.1什麼是可迭代對象、如何判斷是否是可迭代對象

在Python中,我們把所有可以迭代的對象統稱爲可迭代對象,有一個類專門與之對應:Iterable。大多數容器也是可迭代的。但還有很多東西是可迭代的。例如打開的文件、打開的套接字等等。在容器通常是有限的情況下,可迭代可以表示無限的數據流。

可迭代對象是可以返回迭代器(目的是返回其所有元素)的任何對象,不一定是數據結構。這聽起來有點尷尬,但是可迭代對象和迭代器之間存在重要區別。

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

怎麼讓一個對象可迭代呢?畢竟,很多時候,我們需要用到的對象不止Python內置的這些數據類型,還有自定義的數據類型。答案就是實現__iter__()方法,只要一個對象定義了__iter__()方法,那麼它就是可迭代對象。

from collections.abc import Iterable
class A():
    def __iter__(self):
        pass
print('A()是可迭代對象嗎:',isinstance(A(),Iterable))

//結果輸出爲:
//A()是可迭代對象嗎: True

只要一個對象定義了__iter__()方法,那麼它就是可迭代對象。

2 迭代器

迭代器是對可迭代對象的改造升級,上面說過,一個對象定義了__iter__()方法,那麼它就是可迭代對象,進一步地,如果一個對象同時實現了__iter__()和__next__()方法,那麼它就是迭代器。

在Python中,也有一個類與迭代器對應:Iterator。所以,要判斷一個類是否是迭代器,只要判斷是否是Iterator類的實例即可。

from collections.abc import Iterable
from collections.abc import Iterator
class B():
    def __iter__(self):
        pass
    def __next__(self):
        pass
print('B()是可迭代對象嗎:',isinstance(B(), Iterable))
print('B()是迭代器嗎:',isinstance(B(), Iterator))

/*
結果輸出如下:
B()是可迭代對象嗎: True
B()是迭代器嗎: True
*/

3 for循環的本質

x = [1, 2, 3]
x = iter(x)
try:
    while True:
        print(next(x))
except StopIteration:
    pass

從上我們可以看出,for循環的本質是先將可迭代對象列表x利用iter(x)調用__iter__()方法,返回迭代器。然後通過next(x)可以調用魔法函數__next__(),實現下一個元素的獲取。

4 生成器

終於,我們到達了目的地!生成器是我最喜歡的Python語言特性。生成器是一種特殊的迭代器,優雅的迭代器。

生成器使您可以像上面的Fibonacci序列迭代器示例一樣編寫迭代器,但是使用簡潔的語法,避免使用__iter __()和__next __()方法編寫類。

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1
    return 'done'

>>> fib(6)
1
1
2
3
5
8
'done'

仔細觀察,可以看出,fib函數實際上是定義了斐波拉契數列的推算規則,可以從第一個元素開始,推算出後續任意的元素,這種邏輯其實非常類似generator。也就是說,上面的函數和generator僅一步之遙。要把fib函數變成generator,只需要把print(b)改爲yield b就可以了:

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

這裏,最難理解的就是generator和函數的執行流程不一樣。函數是順序執行,遇到return語句或者最後一行函數語句就返回。而變成generator的函數,在每次調用next()的時候執行,遇到yield語句返回,再次執行時從上次返回的yield語句處繼續執行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章