Python – Iteration , Iterable & Iterator

測試環境為 CentOS 8 x86_64 (虛擬機)

原來一個 For 迴圈的知識量這麼大.

[root@localhost ~]# python3
Python 3.6.8 (default, Mar 25 2022, 11:15:52)
[GCC 8.5.0 20210514 (Red Hat 8.5.0-10)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> for i in range(1,4):
...     print(i)
...
1
2
3

先來看看什麼是 Iteration , Iterable 與 Iterator

參考文章 – https://medium.com/citycoddee/python%E9%80%B2%E9%9A%8E%E6%8A%80%E5%B7%A7-6-%E8%BF%AD%E4%BB%A3%E9%82%A3%E4%BB%B6%E5%B0%8F%E4%BA%8B-%E6%B7%B1%E5%85%A5%E4%BA%86%E8%A7%A3-iteration-iterable-iterator-iter-getitem-next-fac5b4542cf4

  • Iteration : 中文翻成迭代,其實就是可以存取 object 裡面的所有所有元素的過程或是機制.
  • Iterable : 可以 Iteration 的 object 都稱為 Iterable , Iterable 的物件包含以下. 官方文件說明 – https://docs.python.org/3/glossary.html#term-iterable
    1. sequence types (序列類) 如 list , str 與 tuple.
    2. non-sequence types (非序列類型) 如 dict 與 file objects.
    3. Object (物件)有使用 __iter__() 或是 __getitem__() method (方法).

    基本上可以 被 for loop 存取 的 objects 都是 Iterable.

  • Iterator:只要有 __iter__ 與 __next__ 的 objects 都是 Iterator. 官方文件說明 – https://docs.python.org/3/glossary.html#term-iterable Iterable

回到剛剛前面的範例 for loop ,這邊透過實作 Iterator (須包含 __iter__ 和 __next__ 方法 (method)) 的範例來了解其運作機制.

for loop in x -> 透過 __iter__ 產生 Iterator -> 透過 __next__ 讀取下一筆資料 直到沒資料為止.

[root@localhost ~]# vi iter1.py
class MyIterator:
    def __init__(self, max_num):
        print('__init__')
        self.max_num = max_num
        self.index = 0

    def __iter__(self):
        print('__iter__')
        return self
        
    def __next__(self):
        print('__next__')
        self.index += 1
        if self.index < self.max_num:
            return self.index
        else:
            raise StopIteration
        
my_iterator = MyIterator(3)

for item in my_iterator:
    print(item)

執行結果

[root@localhost ~]# python3 iter1.py
__init__
__iter__
__next__
1
__next__
2
__next__

說明:
產生 my_iterator 物件,初始化呼叫 __init__ .

my_iterator = MyIterator(3)
    def __init__(self, max_num):
        print('__init__')
        self.max_num = max_num
        self.index = 0

執行結果

__init__

for 迴圈.

for item in my_iterator:
    print(item)

我們 __iter__ 只有簡單 Resturn self 但其實會返回一個疊代器(iterator),透過該疊代器的 __next__() 方法來獲取疊代器的下一個元素.

    def __iter__(self):
        print('__iter__')
        return self
        
    def __next__(self):
        print('__next__')
        self.index += 1
        if self.index < self.max_num:
            return self.index
        else:
            raise StopIteration

執行結果 ( __iter__ 產生疊代器只會執行一次).

__iter__

疊代器透過 __next__() 方法獲取下一個元素.

__next__
1
__next__
2
__next__

但上面範例會有一個問題,產生的 my_iterator 只能 for loop 一次,來看一下下面範例.

[root@localhost ~]# vi iter2.py
class MyIterator:
    def __init__(self, max_num):
        self.max_num = max_num
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        self.index += 1
        print('index' , self.index)
        if self.index < self.max_num:
            return self.index
        else:
            raise StopIteration

my_iterator = MyIterator(3)
for item in my_iterator:
    print(item)

for item in my_iterator:
    print(item)

執行結果

[root@localhost ~]# python3 iter2.py

第一次 for loop

index 1
1
index 2
2
index 3

第二次 for loop

index 4

說明:
可以看到第二次的 loop 並沒有輸出結果,因該疊代器指標 self.index (4) 已經大於 self.max_num (3) ,所以不會執行,下面範例會更清楚.

>>> my_list = [0 , 1 , 2 , 3 , 4]
>>> my_iter=iter(my_list)
>>> next(my_iter)
0
>>> next(my_iter)
1
>>> next(my_iter)
2
>>> next(my_iter)
3
>>> next(my_iter)
4
>>> next(my_iter)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

為了避免這樣的問題,可以使用其他方式來解決,如 Generator 物件 (Object) , yield 或是 __getitem__ 方法 (Method).

沒有解決問題,試試搜尋本站其他內容

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料