生成器
??什么是生成器?提到生成器,往往離不開另一個概念:迭代器,我們知道的迭代器有兩種:一種是調(diào)用方法直接返回的,一種是可迭代對象通過執(zhí)行iter方法得到的,迭代器有的好處是可以節(jié)省內(nèi)存。如果在某些情況下,我們也需要節(jié)省內(nèi)存,就只能自己寫。我們自己用python寫的能實(shí)現(xiàn)迭代器功能的東西就叫生成器。 生成器分為兩種:
- 生成器函數(shù):常規(guī)函數(shù)定義,但是,使用yield語句而不是return語句返回結(jié)果。yield語句一次返回一個結(jié)果,在每個結(jié)果中間,掛起函數(shù)的狀態(tài),以便下次重它離開的地方繼續(xù)執(zhí)行
- 生成器表達(dá)式:類似于列表推導(dǎo),但是,生成器返回按需產(chǎn)生結(jié)果的一個對象,而不是一次構(gòu)建一個結(jié)果列表
生成器函數(shù)
??一個包含yield關(guān)鍵字的函數(shù)就是一個生成器函數(shù)。yield可以為我們從函數(shù)中返回值,但是yield又不同于return,return的執(zhí)行意味著程序的結(jié)束,調(diào)用生成器函數(shù)不會得到返回的具體的值,而是得到一個可迭代的對象。每一次獲取這個可迭代對象的值,就能推動函數(shù)的執(zhí)行,獲取新的返回值。直到函數(shù)執(zhí)行結(jié)束。見下:
def func(x): #定義一個函數(shù),計(jì)算給定數(shù)階乘
for i in range(x):
yield i * i #有yield利用yield關(guān)鍵字返回結(jié)果,每次只返回一個
for j in func(5):
print(j)
0
1
4
9
16
同樣使用普通函數(shù)來實(shí)現(xiàn)上述功能,會明顯發(fā)現(xiàn)生成器函數(shù)代碼少于普通函數(shù)。最為關(guān)鍵的是生成器函數(shù)要更節(jié)省內(nèi)存
def func1(x):
li = []
for i in range(x):
li.append(i)
for j in func(5):
print(j)
0
1
4
9
16
next和send關(guān)鍵
??由于生成器函數(shù)本質(zhì)上是迭代器,所以生成器的接收參數(shù)也是借助next關(guān)鍵字實(shí)現(xiàn)。但同時,生成器函數(shù)還有一個send關(guān)鍵字同樣可以接收參數(shù),那么二者有什么區(qū)別呢?
def func1():
count = yield 6
print(count)
count1 = yield 7
print(count1)
yield 8
g = func1()
print(next(g))
print(g.__next__())
print(g.send('太白'))
6
None
7
太白
8
send 獲取下一個值的效果和next基本一致,只是在獲取下一個值的時候,給上一yield的位置傳遞一個數(shù)據(jù)。
使用send的注意事項(xiàng)
- 第一次使用生成器的時候 是用next獲取下一個值
- 最后一個yield不能接受外部的值
列表推導(dǎo)式與生成器表達(dá)式
??列表推導(dǎo)式是生成滿足一定規(guī)律的列表的簡單方式,其只需一行代碼便可生成一個較為復(fù)雜的列表,在節(jié)省代碼方面大有可為。以下用代碼來詳細(xì)解釋:
# 需求:要求生成一個存放1-30以內(nèi)所有能被3整除的列表。按照原來的方法會是這樣:
li = []
for i in range(1,31):
if i % 3 == 0:
li.append(i)
print(li)
#而有了列表推導(dǎo)式后,此代碼可以被省略為一行:
print([i for i in range(1,31) if i % 3 == 0])
[3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
[3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
列表推導(dǎo)式通??梢苑譃閮煞N:
- 循環(huán)模式:[變量(加工后的變量) for 變量 in iterable]
- 篩選模式:[變量(加工后的變量) for 變量 in iterable if 條件]
#循環(huán)模式
#1到10中每個數(shù)的平方b
[i*i for i in range(1,12)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]
#篩選模式
#找到嵌套列表中名字含有兩個‘e’的所有名字
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
[i for x in names for i in x if i.count('e') == 2 ]
['Jefferson', 'Wesley', 'Steven', 'Jennifer']
列表生成器
把列表解析的[]換成()得到的就是生成器表達(dá)式
列表解析與生成器表達(dá)式都是一種便利的編程方式,只不過生成器表達(dá)式更節(jié)省內(nèi)存
Python不但使用迭代器協(xié)議,讓for循環(huán)變得更加通用。大部分內(nèi)置函數(shù),也是使用迭代器協(xié)議訪問對象的。
sum(x ** 2 for x in range(4))
14