1. 程式人生 > >Python列表生成器與生成器

Python列表生成器與生成器

一、列表生成器

列表生成式即List Comprehensions

>>>list(range(1,5))
[1, 2, 3, 4]
>>>[x * x for x in range(1, 5)] // 即直接生成x平方的列表
[1, 4, 9, 16]
// 加判斷 只生成偶數的平方

[x * x for x in range(1, 11) if x % 2 == 0]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
// 兩層迴圈
// range(1,5)為[1,2,3,4]  range(5,9)為[5,6,7,8
] >>>x + y for x in range(1, 5) for y in range(5, 9) [6, 8, 10, 12]

二、生成器

上面我們提到的列表生成器,是直接建立了一個列表,顯而易見,當數量很大時,直接建立一個列表,相當佔記憶體。
所以,如果列表元素可以按照某種演算法推算出來,那我們是否可以在迴圈的過程中不斷推算出後續的元素呢?這樣就不必建立完整的list,從而節省大量的空間。在Python中,這種一邊迴圈一邊計算的機制,稱為生成器:generator。

我們用列表生成器的時候用的是 [ ],而我們如果用( ),那麼我們就建立了一個生成器。

參考廖老師的例子

>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>

我們可以通過 next() 函式來獲得生成器內的資料

>>> next(g)
0
>>> next(g)
1
>>> next
(g) 4 >>> next(g) 9 >>> next(g) 16 >>> next(g) 25 >>> next(g) 36 >>> next(g) 49 >>> next(g) 64 >>> next(g) 81 >>> next(g) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration

當我們建立好了一個生成器之後,可以用for迴圈讀取資料
此外:
當一個函式內,我們用到了 yeild 函式,那麼這個函式就變成了一個generator
比如,斐波拉契數列(Fibonacci):

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return 'done'
>>> f = fib(6)
>>> f
<generator object fib at 0x104feaaa0>

這裡,最難理解的就是generator和函式的執行流程不一樣。函式是順序執行,遇到return語句或者最後一行函式語句就返回。而變成generator的函式,在每次呼叫next()的時候執行,遇到yield語句返回,再次執行時從上次返回的yield語句處繼續執行。
獲得數列的結果:

>>> for n in fib(6):
...     print(n)
...
1
1
2
3
5
8