Python疊代器


疊代器是可以疊代的物件。 在本教學中,您將了解疊代器的工作原理,以及如何使用__iter____next__方法構建自己的疊代器。

疊代器在Python中無處不在。 它們優雅地實現在迴圈,推導,生成器等中,但隱藏在明顯的視覺中。

Python中的疊代器只是一個可以疊代的物件。一個將一次返回資料的物件或一個元素。

從技術上講,Python疊代器物件必須實現兩個特殊的方法__iter__()__next__(),統稱為疊代器協定。

如果我們從中獲取一個疊代器,那麼一個物件被稱為iterable。 大多數Python中的內建容器是列表,元組,字串等都是可疊代的。

iter()函式(這又呼叫__iter__()方法)返回一個疊代器。

通過Python中的疊代器迭代

使用next()函式來手動遍歷疊代器的所有專案。當到達結束,沒有更多的資料要返回時,它將會引發StopIteration。 以下是一個例子。

# define a list
my_list = [4, 7, 0, 3]

# get an iterator using iter()
my_iter = iter(my_list)

## iterate through it using next() 

#prints 4
print(next(my_iter))

#prints 7
print(next(my_iter))

## next(obj) is same as obj.__next__()

#prints 0
print(my_iter.__next__())

#prints 3
print(my_iter.__next__())

## This will raise error, no items left
next(my_iter)

更優雅的自動迭代方式是使用for迴圈。 使用for迴圈可以疊代任何可以返回疊代器的物件,例如列表,字串,檔案等。

>>> for element in my_list:
...     print(element)
...     
4
7
0
3

迴圈如何實際工作?

在上面的例子中看到的,for迴圈能夠自動通過列表疊代。

事實上,for迴圈可以疊代任何可疊代物件。我們來仔細看一下在Python中是如何實現for迴圈的。

for element in iterable:
    # do something with element

實際上它是以類似下面的方式來實現的 -

# create an iterator object from that iterable
iter_obj = iter(iterable)

# infinite loop
while True:
    try:
        # get the next item
        element = next(iter_obj)
        # do something with element
    except StopIteration:
        # if StopIteration is raised, break from loop
        break

所以在for的內部,for迴圈通過在可疊代的物件上呼叫iter()來建立一個疊代器物件iter_obj

有意思的是,這個for迴圈實際上是一個無限迴圈~..~。

在迴圈中,它呼叫next()來獲取下一個元素,並使用該值執行for迴圈的主體。 在所有物件耗盡後,引發StopIteration異常,內部被捕獲從而結束回圈。請注意,任何其他型別的異常都將正常通過。

在Python中構建自己的Iterator

構建疊代器在Python中很容易。只需要實現__iter__()__next__()方法。

__iter__()方法返回疊代器物件本身。如果需要,可以執行一些初始化。

__next__()方法必須返回序列中的下一個專案(資料物件)。 在到達結束後,並在隨後的呼叫中它必須引發StopIteration異常。

在這裡,我們展示一個例子,在每次疊代中給出下一個2的幾次方。 次冪指數從零開始到使用者設定的數位。

class PowTwo:
    """Class to implement an iterator
    of powers of two"""

    def __init__(self, max = 0):
        self.max = max

    def __iter__(self):
        self.n = 0
        return self

    def __next__(self):
        if self.n <= self.max:
            result = 2 ** self.n
            self.n += 1
            return result
        else:
            raise StopIteration

現在可以建立一個疊代器,並通過它疊代如下 -

>>> a = PowTwo(4)
>>> i = iter(a)
>>> next(i)
1
>>> next(i)
2
>>> next(i)
4
>>> next(i)
8
>>> next(i)
16
>>> next(i)
Traceback (most recent call last):
...
StopIteration

也可以使用for迴圈疊代那些疊代器類。

>>> for i in PowTwo(5):
...     print(i)
...     
1
2
4
8
16
32

Python無限疊代器

疊代器物件中的專案不必都是可耗盡的,可以是無限疊代器(永遠不會結束)。 處理這樣的疊代器時一定要小心。

下面是用來演示無限疊代器的一個簡單的例子。

內建的函式iter()可以用兩個引數來呼叫,其中第一個引數必須是可呼叫物件(函式),而第二個引數是檔頭。疊代器呼叫此函式,直到返回的值等於指定值。

>>> int()
0

>>> inf = iter(int,1)
>>> next(inf)
0
>>> next(inf)
0

可以看到,int()函數總是返回0,所以將它作為iter(int,1)傳遞將返回一個呼叫int()的疊代器,直到返回值等於1。這從來沒有發生,所以這樣就得到一個無限疊代器。

我們也可以建立自己的無限疊代器。 以下疊代器理論上將返回所有奇數。

class InfIter:
    """Infinite iterator to return all
        odd numbers"""

    def __iter__(self):
        self.num = 1
        return self

    def __next__(self):
        num = self.num
        self.num += 2
        return num

範例執行如下 -

>>> a = iter(InfIter())
>>> next(a)
1
>>> next(a)
3
>>> next(a)
5
>>> next(a)
7

當迭代這些型別的無限疊代器時,請注意指定終止條件。

使用疊代器的優點是它們可以節省資源。 如上所示,我們可以獲得所有奇數,而不將整個系統儲存在記憶體中。理論上,可以在有限的記憶體中計算有無限的專案。