python之路 生成器

2021-08-04 07:33:18 字數 3481 閱讀 5392

顧名思義,列表生成式就是通過某種方式來生成乙個列表,那麼 ok,我們可以通過哪幾種方式來生成呢?

from collections import iterable

list_1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

defadd

(x):

return x + 2

result = map(add, list_1)

print(type(result))

print(isinstance(result, iterable))

print—>:

class 『map』

true

可以看到返回的結果是乙個map型別的可迭代物件,map函式的作用就是將列表中的每乙個元素傳遞到函式中,並將函式返回的結果包裝成乙個可迭代的物件。

看完這種形式,我們再來看看另外一種形式的高逼格map函式:

from collections import iterable

list_1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

list_2 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

list_3 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

defadd

(x, y, z):

return x + y + z

result = map(add, list_1, list_2, list_3)

for x in result:

print(x)

print(type(result))

print(isinstance(result, iterable))

print—>:

0 3

6 9

12 15

18 21

24 27

class 『map』

true

通過列表生成式的形式,我們可以直接建立乙個列表。

list_4 = [x for x in range(0, 10)]

print(list_4)

print—>:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

通過這種方式我們建立了乙個包含10個元素的列表,如果我們需要建立乙個包含100萬個元素的列表呢?一般來說計算機的記憶體都是有限制的,而且建立乙個100萬個元素的列表,如果我們只用到前面幾個,那麼顯然是很浪費記憶體空間的,程式的執行效率也會很低的。

so,聰明的人類就會想到,如果不把列表一次性建立出來,而是元素可以通過某種演算法推算出來,那豈不是不用占用這麼大的記憶體了。這就是生成器的作用。

from collections import iterable

g = (x for x in range(10))

g = (x for x in range(10))

print(g)

print(type(g))

print(isinstance(g, iterable))

print—>:

generator object genexpr at 0x0000022ef0c64e60

class 『generator』

true

那麼我們如何來遍歷生成器呢?剛才我們說過生成器並不是乙個集合形式的資料型別,我們可以將其理解成可進行推算的一種演算法。在python中我們可以通過呼叫next函式來進行這種推算。

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 "", line 1, in

stopiteration

當然,上面這種不斷呼叫next(g)實在是太**了,正確的方法是使用for迴圈,因為generator也是可迭代物件:

for i in g:

print(i)

print—>:

0 1

2 3

4 5

6 7

8 9

所以我們建立好乙個generator後,基本都是用for迴圈來遍歷,畢竟next這種方式實在是太麻煩了,所以我們基本不用關心stopiteration異常。

generator非常強大。如果推算的演算法比較複雜,用類似列表生成式的for迴圈無法實現的時候,還可以用函式來實現。

比如,著名的斐波拉契數列(fibonacci),除第乙個和第二個數外,任意乙個數都可由前兩個數相加得到:

1, 1, 2, 3, 5, 8, 13, 21, 34, …

斐波拉契數列用列表生成式寫不出來,但是,用函式把它列印出來卻很容易:

def

fib(num):

n, a, b = 0, 1, 1

while n < num:

print(a)

a, b = b, a + b

n = n + 1

fib(10)

print—>:

1 1

2 3

5 8

13 21

34 55

仔細觀察,可以看出,fib函式實際上是定義了斐波拉契數列的推算規則,可以從第乙個元素開始,推算出後續任意的元素,這種邏輯其實非常類似generator。

也就是說,上面的函式和generator僅一步之遙。要把fib函式變成generator,只需要把print(b)改為yield b就可以了:

def

fib(num):

n, a, b = 0, 1, 1

while n < num:

yield (a)

a, b = b, a + b

n = n + 1

fib(10)

print(fib(10))

for i in g:

print(i)

print—>:

1 1

2 3

5 8

13 21

34 55

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

Python成長之路 生成器

了解生成器 我們知道迭代器有兩種 一種是呼叫方法直接放回的 一種是可迭代物件執行iter方法得到的。迭代器的有點是可以節省記憶體。如果在某些情況下,我們也需要節省記憶體,就只能是自己寫,我們自己寫的這個能實現迭代器功能的東西就叫做生成器。生成器的函式 常規函式定義,但是,使用的是yield語句而不是...

python之路 再談生成器

對於普通的生成器,第乙個next呼叫,相當於啟動生成器,會從生成器函式的第一行 開始執行,直到第一次執行完yield語句 第4行 後,跳出生成器函式。然後第二個next呼叫,進入生成器函式後,從yield語句的下一句語句 第5行 開始執行,然後重新執行到yield語句,執行後,跳出生成器函式,後面再...

python之路 函式迭代,生成器

恢復內容開始 dir 被測物件 如果它含有 iter 那這個物件叫做可迭代物件,遵循可迭代協議。可迭代物件 iterable 可以轉換 迭代器 如何實現 都像內部定義乙個 iter 方法 迭代器 iterator 遵循迭代器協議 1,只含有 iter 方法的資料是課迭代的物件 l 1,2,3,4 p...