探討 Python 的生成器(Generator) - tsungjung411/python-study GitHub Wiki

為什麽 Pyhton 需要生成器(Generator)?

  • 若使用 for 迴圈,一般只能使用 range(...), enumerate(...)。
    若使用 range(100000),則會產生 100000 個整數的清單,太佔記憶體空間了

  • 若改用 while 迴圈控制,自己控制 i=i+1,就可以不需要 generator 了吧?
    看起來是,所以感覺 generator 是多餘的?

  • 但是如果把 while 的迴圈控制,打包成一個小函數,讓程式碼的可讀性高一點(Model 複雜產生元素, View 負責顯示),這時候 generator 就派上用場

生成器(Generator)的簡易範例

程式碼:

even_list = [even for even in range(2,20,2)]
print('from the even list: ')
for even in even_list:
    print(even)
# end-of-for

# 把上述的 [...] 直接換成 (...),就是一個 generator
even_generator = (even for even in range(2,20,2))
print('from the even generator: ')
for even in even_generator:
    print(even)
# end-of-for

執行結果:

from the even list: 
2
4
6
8
10
12
14
16
18
from the even generator: 
2
4
6
8
10
12
14
16
18

生成器(Generator)的複雜範例

程式碼:

def from_to(start, end):
    idx = start
    while idx < end:
        yield idx  # 執行後,後續的執行會暫停,並回傳 idx
        idx = idx + 1
    # end-of-while
# end-of-def

# 呼叫 from_to 生成器
for idx in from_to(10, 20):
    print(idx)
# end-of-for

執行結果:

10
11
12
13
14
15
16
17
18
19

可以不用一次產生所有的整數,因此可以省去記憶體的空間


如何測試與設計「複雜」的生成器(Generator)?

  • 先用 print 輸出,測試沒問題,再把 print 換成 yield

程式碼:

def from_to(start, end):
    idx = start
    while idx < end:
        print(idx) # 測試沒問題了,把 print 換成 yield, generator 就大功告成
        idx = idx +1
    # end-of-while
# end-of-def

# 呼叫 from_to 函數
from_to(10, 20)

執行結果:

10
11
12
13
14
15
16
17
18
19

透過生成器(Generator),讓程式碼可讀性變高的範例

  • Model 複雜產生元素, View 負責顯示

程式碼:

# Model part
def fib(max):
    '''
    費波那西數列(Fibonacci Sequence)
    idx: 0, 1, 2, 3, 4, 5, 6
    fib: 0, 1, 1, 2, 3, 5, 8
    '''
    n, a, b = 0, 0, 1
    while a <= max:
        # print('[{}] {}'.format(n, a))
        yield a
        a, b = b, a + b
        n = n + 1
    # end-of-while
# end-of-def

# View part
for n in fib(100):
    print(n)
# end-of-def

執行結果:

0
1
1
2
3
5
8
13
21
34
55
89

生成器(Generator)的真正核心精神

  • 可以逐步生成下一個迭代的參數

參考文章

⚠️ **GitHub.com Fallback** ⚠️