iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 18
0
Data Technology

30天python雜談系列 第 18

iterator和generator雜談之一———剖析for in內部機制

python iterator和generator雜談之一

科科其實這篇文是我在知道這個比賽的更久以前寫的,是我人生第一篇技術文,然後我就把他搬上來佔比賽天數了,但因為文筆拙劣,我刪減了很多不正確的資料(雖然刪減後還是可能有些錯誤),要發這篇文之前我東想西想,想再多加點東西,但總是發現還是有人寫的好多了,讓我看的深感佩服,然後變得滿腦子都是他的概念了,因為照著這樣寫下去感覺像是抄襲,所以就索性把他的連結給貼上來。

在介紹python的iterator與generator物件前,要先講一下iteration(迭代)的概念,如果就我的程式經驗來說,iteration這個概念通常會用在一個list或是一個array的traversal(遍歷),也就是我們在python裡經常用到的for....in...語法:

example1.py:

mylist = [2,4,6,8,10]

for  i  in  mylist:

print(i)  # 會依序print出 2 4 6 8 10

# 這三行程式會依序迭代(也可以說是遍歷)mylist裏面的5個物件

接下來深入探討一下for in語法內部究竟是怎麼執行的,同時也會開始帶進iterator的使用,實際上前述example1的for in的語法裏面調用了兩個函數:
(1) _iter_:回傳一個iterator物件,而這個物件可以呼叫__next__函數。
(2) _next_:這個函數會實際執行iterator物件的迭代行為。

至於__next__裡所執行的迭代行為是怎麼一回事,我們可以把example1的for in語法拆解成__iter__和__next__執行:

In python3 shell:
>>> mylist = [2,4,6,8,10]
>>> mylist_iterator = iter(mylist) # 這個iter()函數會調用python預設的mylist.__iter__函數,並回傳一個iterator物件,然後我們用mylist_iterator這個變數來儲存這個iterator物件
>>> # 開始迭代
>>> i = next(mylist_iterator) # i = 2 , next()函數會調用python預設的mylist_iterator.__next__函數
>>> print(i)
2
>>> i = next(mylist_iterator) # i = 4
>>> print(i)
4
>>> i = next(mylist_iterator) # i = 6
>>> print(i)
6
>>> i = next(mylist_iterator) # i = 8
>>> print(i)
8
>>> i = next(mylist_iterator) # i = 10
>>> print(i)
10
>>> i = next(mylist_iterator) 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> # 當最後一個元素遍歷完,再呼叫mylist_iterator.__next__就會跑出一個 StopIteration 的例外,一般for in在呼叫__next__的過程中遇到了 StopIteration 就會自動停止 for loop的執行

從example2的例子可以看出這個預設的__next__所執行的迭代行為可以理解為iterator物件裏面有很多元素,而當下有一個指針指向其中一個元素A,若呼叫了__next__則會回傳這個元素A的下一個元素B,同時這個指針也會轉向元素B。

然後再很粗淺的總結一下iterator的意義:能夠辨認一個物件是否為一個iterator最重要的就是他能不能執行迭代行為,也就是他有沒有定義__next__函數。

本文稍微解構了一下for in語法的底層運作以及探討iterator的粗略定義,若要再深入探究iterator的詳細定義,我推荐kissg網友的詮釋:
http://kissg.me/2016/04/09/python-generator-yield/


上一篇
版本差異雜談之七———今天先讓自己input()一下
下一篇
iterator和generator雜談之二———懶惰的generator
系列文
30天python雜談30

尚未有邦友留言

立即登入留言