生成器的概念
生成器是一個函數,它會記住每一次調用的數據狀態和在流控制構造中的位置。在下一次調用時,所有參數都是第一次調用時所保留的,而不是新創建的。
列表生成式
作爲對比,先來介紹一下列表生成式List Comprehensions。
生成一個0-9的列表:
#方式一:
a=list(range(10))
print(a)
結果:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
#方式二:
b=[x for x in range(10)]
print(b)
結果:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
加入條件判斷的列表生成式:
def f(n):
return n*n
c=[f(x) for x in range(10) if x%2==0]
print(c)
結果:
[0, 4, 16, 36, 64]
多參數的列表生成式:
d={'Bob':18,'Allice':20,'Cinda':17}
for m,n in d.items():
print(m,"'s age=",n)
結果:
Allice 's age= 20
Bob 's age= 18
Cinda 's age= 17
小結:
使用列表生成式可以用很簡潔的代碼快速生成List,但是當列表元素特別巨大或者無限的時候,使用就會佔用過多內存甚至報錯。
生成器
生成器generator就能克服列表生成器存在的一些不足,它不必一次性創建完整的List,而是在循環的過程中不斷推算後續的元素,一邊循環一邊計算。
定義方式:
1.將列表生成器的[]改爲()就創建了一個generator。
s=(x for x in range(10))
print(s)
print(next(s))#等價於s.__next__()
print(next(s))
print(next(s))
print(next(s))
for i in s:
print(i)
輸出結果:
<generator object <genexpr> at 0x00000216FEA3C048>
0
1
2
3
4
5
6
7
8
9
因爲生成器能記錄狀態,所以在運行for循環代碼的時候它不是從頭開始計算,而是從當前狀態開始往後循環。
2.使用yield。
如果一個函數的定義裏面含有yield關鍵字,那麼這個函數就不再是一個普通函數,而是一個generator。
- 函數一般會順序執行,遇到return等語句或者執行到最後一行函數語句就會返回。
- 區別於一般函數,generator在每次調用next()的時候,生成器函數運行到yield之處,返回yield後面的值且在這個地方暫停,所有的狀態都會被保持住,直到下次next函數被調用,或者碰到異常循環退出
def pir():
print('first')
yield "a"
print('second')
yield "b"
print('last')
yield "c"
輸出結果:
first
second
b
last
c