測試環境為 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
- sequence types (序列類) 如 list , str 與 tuple.
- non-sequence types (非序列類型) 如 dict 與 file objects.
- 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).