
上次推文我們一起學(xué)習(xí)了python中的高級函數(shù)——Python實(shí)用教程系列——高階函數(shù)Map、Filter、Reduce。推文中重點(diǎn)介紹了map,filter和reduce中相關(guān)概念,也通過實(shí)例的方式介紹了這些函數(shù)的實(shí)際用法,大家可以好好學(xué)習(xí)一下。
有小伙伴對推導(dǎo)式和Lambda的相關(guān)知識不是很清楚,需要我寫一些容易理解的教程,所以這次推文我們就來聊一聊推導(dǎo)式的相關(guān)知識。
一、推導(dǎo)式定義
推導(dǎo)式 comprehensions(又稱解析式),是 Python 的一種獨(dú)有特性。推導(dǎo)式最主要的特點(diǎn)就是可以從一個數(shù)據(jù)序列構(gòu)建另一個新的數(shù)據(jù)序列。在Python 中目前常用的推導(dǎo)式有列表推導(dǎo)式、字典推導(dǎo)式和集合推導(dǎo)式。
二、列表推導(dǎo)式
列表推導(dǎo)式是我們最常使用的,因?yàn)榱斜硎俏覀冏畛J褂玫模浠镜恼Z法示意如下:
- [表達(dá)式 for 變量 in 列表]
- [表達(dá)式 for 變量 in 列表 if 條件]
上述表達(dá)式中”[]”是表示Python中的列表。從基本的語法形式上我們看得出來,變量是我們預(yù)先就存在的列表的值,或者是對存在的列表進(jìn)行條件篩選后的值。
我們來看幾個具體的例子就清晰了:
2.1 第一種語法形式
list_a = range(1,10)
list_b = [each for each in list_a]
print(list_b)
# 輸出 [1, 2, 3, 4, 5, 6, 7, 8, 9]
2.2 第二種語法形式
# 輸出 list_a中的基數(shù)
list_a = range(1,10)
list_b = [each for each in list_a if each % 2 ==1]
print(list_b)
# 輸出 [1, 3, 5, 7, 9]
第二種語法形式生成的結(jié)果與第一種不同的原因在于,第二種語法形式中使用了篩選條件:each % 2 ==1
注意list_b使用了”[]”,這就說明了其為一個列表。有的小伙伴還沒看出來的話,我們使用for將第二種形式進(jìn)行改寫:
list_b = []
list_a = range(1,10)
for each in list_a:
if each % 2 == 1:
list_b.append(each)
print(list_b)
輸出結(jié)果為list_a中的奇數(shù)組成的列表,if each % 2 == 1在第二種形式中也完全顯示了,可以看出使用列表推導(dǎo)式可以精簡代碼,閱讀起來更加有Python的風(fēng)格。
這里給大家設(shè)置兩個小題目,大家試著解決:
(1)過濾掉列表
names = ['gongsunli’,’machao’,’Gongben’,’Yuji’]中長度大于或等于4的字符串列表,并將剩下字符的轉(zhuǎn)換成大寫字母,結(jié)果保存為列表。
(2)給定列表A=[a,b,c], B=[d,e,f]],找出A和B中元素可以組成的字符串的所有可能,如ab.
三、字典推導(dǎo)式
學(xué)習(xí)了列表推導(dǎo)式以后,學(xué)習(xí)字典推導(dǎo)式就沒什么困難了,字典推導(dǎo)式語法差不多,只不過我們使用”{}”產(chǎn)生的是字典而已,唯一要注意的就是在字典中有鍵和值兩個關(guān)鍵的屬性,仿似列表推導(dǎo)式,那么其基本的語法可以被寫作這樣:
- { 鍵:值 for 鍵,值 in 數(shù)據(jù)結(jié)構(gòu)}
- { 鍵:值 for 鍵 in 數(shù)據(jù)結(jié)構(gòu)1 for 值 in 數(shù)據(jù)結(jié)構(gòu)2 }
同樣我們來看幾個實(shí)際的小例子:
3.1 第一種語法形式
list_c = ['我愛','Python學(xué)堂']
dict_c = {k:v for v,k in enumerate(list_c)}
print(dict_c)
# 輸出:{'我愛': 0, 'Python學(xué)堂': 1}
3.2 第二種語法形式
list_a = ['我愛']
list_b = ['Python學(xué)堂']
dict_a = {key: value for key in list_a for value in list_b}
print(dict_a)
#輸出:{'我愛': 'Python學(xué)堂'}
上述代碼塊1中使用了Python的內(nèi)置函數(shù)enumerate()。有基礎(chǔ)的小伙伴一看就知道,enumerate()可將一個可遍歷的數(shù)據(jù)對象(如列表、元組或字符串)組合為一個索引序列,同時列出數(shù)據(jù)下標(biāo)和數(shù)據(jù)。代碼塊2的最后生成的結(jié)果是一個字典(或常使用生成Json數(shù)據(jù)),第二種的字典推導(dǎo)式是非常常見的,大家要掌握好。
再看一個例子:
# 遍歷一個有鍵值關(guān)系的可迭代對象
pro_city = [('江蘇', '南京'), ('福建', '福州'), ('北京', '北京')]
dict_d = {key: value for key, value in pro_city}
print(dict_d)
# {'江蘇': '南京', '福建': '福州', '北京': '北京'}
再如:
dict_e = {key: key * key for key in [1,2,3]}
print(dict_e)
基本上字典推導(dǎo)式就這些,只不過在平時的使用中我們使用一些其他的技巧就能產(chǎn)生一些奇妙的現(xiàn)象。
四、集合推導(dǎo)式
集合我們都很了解,就是一個沒有重復(fù)元素的匯集,跟列表和字典推導(dǎo)式類似,其基本的語法形式可以表示為:
- { 表達(dá)式for 項(xiàng)in 序列if 條件}
我們先看看集合“{}”,因?yàn)槠涫遣恢貜?fù)的,因此如果有語句:print({1,2,3,4,4,5})會輸出:1,2,3,4,5,重復(fù)的4將會被刪除。
接著我們來看集合的相關(guān)例子:
# 遍歷一個有鍵值關(guān)系的可迭代對象
string_var = '我愛Python學(xué)堂'
res = {value for value in string_var}
print(res)
#輸出為{'h', 'y', 'o', 'P', '我', '愛', '學(xué)', 'n', '堂', 't'}
由于集合是無序性的,因此我們再次運(yùn)行上述代碼的時候,會得到不同的結(jié)果的,比如我們可能得到:
{'我', 'y', 'o', 't', 'h', 'n', '學(xué)', '愛', 'P', '堂'},
{'我', 't', 'o', 'y', 'n', '堂', 'h', '愛', '學(xué)', 'P'}等等。
以上就是推導(dǎo)式相關(guān)的內(nèi)容了,我們再來看一個很好玩的東西,很酷炫的表達(dá)式:lambda表達(dá)式。
五、Lambda表達(dá)式
在Java 和Python中均提供了一個Lambda表達(dá)式,這個表達(dá)式又被稱為匿名函數(shù),是現(xiàn)代各種編程語言爭相引入的一種語法,它設(shè)計精巧,在很大程度上可以精簡代碼,就像推導(dǎo)式一樣。
我們之前的推文講述了map、reduce、filter等函數(shù)都支持函數(shù)作為參數(shù),而Lambda函數(shù)就可以應(yīng)用在函數(shù)式編程中。其基本語法可以簡述如下:
- Lambda [參數(shù)1[參數(shù)2, … 參數(shù)n]]: 表達(dá)式
參數(shù)的數(shù)量是不固定的,可選的。
我們來看看這個函數(shù)和我們自定義的函數(shù)之間有什么差異,假設(shè)我們現(xiàn)在計算兩個數(shù)的和:
5.1 自定義方式
def add_two(x,y):
return x + y
print(add_two(1,2))
5.2 Lambda方式
res = lambda x,y:x+y
print(res(1,2))
他們的差別很明顯:Lambda能夠出現(xiàn)在Python語法不允許def出現(xiàn)的地方,def定義的函數(shù)一般用來處理比較復(fù)雜的功能,而Lambda用來處理一些簡單的操作。
之前的推文中,我們講述了一些map、reduce、filter函數(shù),如果這些函數(shù)和Lambda結(jié)合起來使用就會產(chǎn)生一些比較高級的操作,比如:
5.3 與map結(jié)合
list_1=[1,2,3]
list_2=[10,20,30]
print(list(map(lambda x,y:x+y,list_1,list_2)))
#輸出 [11, 22, 33]
5.4 與reduce結(jié)合
from functools import reduce
print(reduce(lambda a,b: a+b ,[1,2,3,4])) # 輸出10
5.5 與filter結(jié)合
num_list = [1,2,3,3,4,5,6,7,8,9,10]
print(list(filter(lambda x : x % 2 == 0, num_list)))
# 輸出 [2, 4, 6, 8, 10]
實(shí)際使用的中,我們可能會遇道更加復(fù)雜的操作,但是沒關(guān)系,只要理解好lambda的精髓這些問題就不是問題啦!
最后總結(jié)一下使用Lambda的好處:
(1)使用 Lambda 表達(dá)式可省去定義函數(shù)的過程,讓代碼更加簡潔。
(2)Lambda 表達(dá)式具有使用后即釋放的特點(diǎn),從這個角度上提升了程序的性能(如內(nèi)存使用)。
六、總結(jié)
本次推文我們講述了Python中的推導(dǎo)式和Lambda表達(dá)式,這些表達(dá)式能很好精簡代碼并且使得代碼更加的具又Python風(fēng)格,實(shí)際項(xiàng)目中我們可使用它們很好解決問題,比如:leetcode中的第937題《重新排列日志》,有興趣的小伙伴可以研究一下。