剛開始寫Python的時候,你可能對於Python的語法for i in [2, 4, 6, 8, 10]
感到驚艷,這種簡潔的語法相比C++或Java來說直觀了許多。然而,你有沒有想過Python在處理for in
的時候,背後到底發生了什麼?什麼樣的object可以被放進for in
loop呢?
Container和Iterator
Container的概念非常簡單,Python中的一切皆為object,而object的集合就是Container,例如list, set, tuple等等。所有的Container都是iterable(可迭代的)。可迭代是什麼意思呢?你可以想像一下你去水果攤買蘋果,老闆不告訴你庫存情況,每次你只需要跟老闆說「我要一個蘋果」,直到老闆告訴你「蘋果沒了」。Container透過iter()
返回一個Iterator,然後我們可以透過next()
就像跟老闆要蘋果那樣,一個一個要。
1 | 1, 2, 3] arr = [ |
當老闆說沒有蘋果的時候,就會throw exception出來。
Generator
Generator可以理解為懶人版的Container。生成一個Container很簡單,[i for i in range(100000000)]
就可以生成一億個int的array,每個元素都會保存在記憶體當中。當然,轉成Iterator後也是,只是他們取用元素的方式不同而已。Generator的使用方法和Iterator類似,都是需要後再取,只是Iterator會預先把所有元素放進記憶體,而Generator會等到需要拿的時候才會把該元素載入記憶體。
1 | import os |
我們可以看到記憶體驚人的差異,在Iterator和Generator初始記憶體都差不多的情況下,Iterator需要2GB的記憶體,而Generator只需要9.5MB。如果遇到不需要同時在記憶體保存這麼多東西的場景,例如元素總和,可以使用Generator。由上面的範例可以看到,Generator的初始化寫法是(i for i in range(100000000))
。
那麼Generator還能怎麼玩呢?例如我們想要驗證一個數學公式{(1+2+3+…+n)^2 = 1^3 + 2^3 + 3^3 + … + n^3}
1 | import time |
yield
是Generator獨有的,你可以理解為在next
之前,它會被卡在這裡,呼叫next
之後yield
就會return值出來。你看,有了Generator,我就能一直無限的驗證下去,不用擔心記憶體爆炸。Iterator是一個有限集合,Generator是一個無限集合!
除此之外,Generator也能讓程式碼更加簡潔有力!讓我們看下面的例子,輸入一個array和一個數字,找出該數字在array的位置。
1 | # Iterator |
顯然的,Generator清爽多了。
總結
本篇講了Container, Iterator和Generator
- Container是Iterable的,代表將Container放進for in裡我們可以一個個迭代
- Generator是一個特殊的Iterator,使用Generator可以寫出更清新,更省資源的程式碼