Python Iterator

Python Iterator 介紹

Python Iterator 常常會和 Iterable object 一起搞混,這篇就來介紹一下 Python 中的 Iterator。

延伸閱讀:Python Iterable Objects 介紹

1. 定義

Python Iterator 的定義為:符合 Python 中的 Iterator Protocol,或是一個有 __iter__()__next__() methods 的 object。

vowels = ['a', 'e', 'i', 'o', 'u']
print(hasattr(vowels, '__iter__'))
True
print(hasattr(vowels, '__next__'))
False

# 可以用 iter() 來宣告 iterator object
vowels_iter = iter(vowels)
print(hasattr(vowels_iter, '__iter__'))
True
print(hasattr(vowels_iter, '__next__'))
True

可以用 collection module 來判斷是不是 iterator:

# Python 3.10+ 請用以下這行 import
from collections.abc import Iterable, Iterator
# Python 3.9- 請用以下這行 import
from collections import Iterable, Iterator

vowels = ['a', 'e', 'i', 'o', 'u']
print(isinstance(vowels, Iterable))
True
print(isinstance(vowels, Iterator))
False

vowels_iter = iter(vowels)
print(isinstance(vowels_iter, Iterable))
True
print(isinstance(vowels_iter, Iterator))
True

2. Iterator v.s. Iterable Object

那 iterator 和 iterable 又什麼差別呢?通常只要可以執行 iteration 的,就可以稱為 iterable object,最單純的方法,就是看可不可以用 for loop 去 iterate 每個 item。

那 Iterator 到底是用來做什麼用的呢?我們可以舉 list object 為例:

宣告了一個 list object 後,Python 會將這個 list object 存在記憶體當中,也因此宣告完 list object 後,你可以隨時取得這個 list object 的任意 item。

但這樣會有一個問題:當這個 list object 有很多 items 的時候,就會吃掉很多記憶體資源,因此 iterator 就是用來解決這類問題的。

list object 的 iterator 版本就稱為 list iterator object。list iterator object 和普通的 list object 最大的不同就在於執行方式,不像 list object 會將所有 items 載入記憶體,list iterator object 宣告後就只能 iterate 所有 items 一次,有點像是,我 iterate 完一個 item 後,就把控制權丟出去,並且只需要記得目前這個 iterator iterate 到哪個 item 就好,等到需要 iterate 的時候,再繼續 iterate 下一個 item,有點類似 linked list 的概念。

因為不需要將所有 items 都載入到記憶體,所以記憶體的用量通常會少滿多的,不過也因此無法存取到這個 list iterator object 的基本屬性,ex: len。

vowels = ['a', 'e', 'i', 'o', 'u']
print(vowels[2])
# 可以隨時取得 list object 的任意元素
'i'

vowels_iter = iter(vowels)
print(vowels_iter[2])
TypeError: 'list_iterator' object is not subscriptable

# 只能用 next 來 iterate iterator 的 items,且執行一次 next,就像是將 linked list 的指標往後挪一個 item
print(next(vowels_iter))
'a'
print(next(vowels_iter))
'e'
print(next(vowels_iter))
'i'
print(next(vowels_iter))
'o'
print(next(vowels_iter))
'u'
# iterate 到最後一個 item 後,再執行 iterator 的話,就會噴 StopIteration 的 exception
print(next(vowels_iter))
StopIteration

記憶體用量比較:

vowels = ['a', 'e', 'i', 'o', 'u']
print(getsizeof(vowels))
104 (Bytes)

vowels_iter = iter(vowels)
print(getsizeof(vowels_iter))
48 (Bytes)

所以,iterator 一定是 iterable object,但 iterable object 不一定是 iterator

3. 宣告 Iterator

3.1 iter function

iter(object)
iter(objectsentinel)
  • 如果沒有傳入第二個 sentinel argument,那第一個 object argument 一定要是 iterable object,否則會 raise TypeError
  • 如果有傳入第二個 sentinel argument,那第一個 object argument 一定要是 callable object,每次 iterate 都會 call object argument 的 __next__() method,如果某個 __next__() 回傳的 value 和 sentinel argument 一樣,那就會 raise StopIteration,停止 iterate
list_instance = [1, 2, 3, 4]
print(iter(list_instance))
<list_iterator object at 0x1024d6410>
class DoubleIt:
    def __init__(self):
        self.start = 1

    def __iter__(self):
        return self

    def __next__(self):
        self.start *= 2
        return self.start
    
    __call__ = __next__

my_iter = iter(DoubleIt(), 16)
print(my_iter)
<callable_iterator object at 0x104873ee0>

for x in my_iter:
    print(x)
2
4
8

3.2 generator

generator 也是一種 iterator,可以參考另一篇文章:Python Generator 介紹

參考資料

Python進階技巧 (6) — 迭代那件小事:深入了解 Iteration / Iterable / Iterator / __iter__ / __getitem__ / __next__ / yield
Python Iterators – W3Schools
Iterator Protocol — Python 3.11.4 documentation
[Python教學]Python Comprehension語法應用教學
Python iter(): iter() Parameters, What is ITER () in Python?

如果覺得我的文章有幫助的話,歡迎幫我的粉專按讚哦~謝謝你!

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top