奇技淫巧,還是正統(tǒng)功夫?Python推導(dǎo)式最全用法

1 Pythonic - 很Python
寫一段代碼生成1到100之間的數(shù)字的平方的列表,答案是:
1,4,9,16...
如果你這樣寫,你就不Pythonic了:
nums?=?[]
for?i?in?range(1,101):
????nums.append(i*i)
print(nums)
正確的寫法是使用Python的推導(dǎo)式:
nums?=?[i*i?for?i?in?range(1,101)]
2 帶條件的推導(dǎo)式
生成一個列表,包含1到100之間是3的倍數(shù)的數(shù)字的方法:
9,36,81...
代碼:
nums?=?[i*i?for?i?in?range(1,101)?if?i%3==0]
3 帶條件的表達式
生成一個列表,如果是3的倍數(shù)就用平方,否則就用是數(shù)字本身:
1,2,9,4,5,36...
代碼:
nums?=?[i*i?if?i%3==0?else?i?for?i?in?range(1,101)]
結(jié)合上面的3個例子,來看一下推導(dǎo)式總結(jié):
推導(dǎo)式從一個可枚舉數(shù)據(jù)(列表,元組,集合,字典等)推導(dǎo)出一個列表。也可以推導(dǎo)出生成器,集合或字典。 推導(dǎo)式可以加推導(dǎo)條件,只對符合條件的元素推導(dǎo) 要推導(dǎo)出的元素使用表達式生成,可以用if else生成不同元素
[表達式?if?表達式條件?else?分支?for?i?in?序列?if?推導(dǎo)條件]
4 使用函數(shù)
如果推導(dǎo)條件或者表達式特別復(fù)雜怎么辦?可以使用函數(shù)。
推導(dǎo)所有1-100之間的所有質(zhì)數(shù):2,3,5,7...
def?is_prime(num):
????if?num?==?1:
????????return?False??
????for?i?in?range(2,num):
???????if?(num?%?i)?==?0:
???????????return?False
????else:
???????return?True
p_nums?=?[i?for?i?in?range(1,100)?if?is_prime(i)]
print(p_nums)
把推導(dǎo)的條件放在函數(shù)中,既可以應(yīng)對復(fù)雜的條件,又可以利用推導(dǎo)式的簡潔寫法。
同理,如果生成推導(dǎo)結(jié)果的過程很復(fù)雜,也可以把邏輯放到函數(shù)中。
推導(dǎo)1900到2021年之間所有的年份,標(biāo)記出閏年,生成結(jié)果:
1900,?1901,?1902,?1903,?'閏1904'
代碼:
def?is_run(year):
????if?(year?%?4)?==?0:
???????if?(year?%?100)?==?0:
???????????if?(year?%?400)?==?0:
???????????????return?True???#?整百年能被400整除的是閏年
???????????else:
???????????????return?False
???????else:
???????????return?True???????#?非整百年能被4整除的為閏年
????else:
???????return?False?
ryears?=?[f'閏{y}'?if?is_run(y)?else?y?for?y?in?range(1900,?2021)]????
print(ryears)
5 嵌套表達式 - 不推薦使用
從2000年到2021年,生成每個月份:'2000年:1月', '2000年:2月', '2020年:3月', ..., '2021年:12月'
monthes?=?[f'{y}年:{m}月'?for?y?in?range(2000,?2022)?for?m?in?range(1,13)?]
這里有兩個for循環(huán),類似于:
monthes?=?[]
for?y?in?range(2000,?2022):
????for?m?in?range(1,13):
????????monthes.append(f'{y}年:{m}月')
是不是下面的特別容易懂?所以兩層的循環(huán)不推薦使用推導(dǎo)式,哈哈。
那我為什么還要講?你會碰到有人這么寫,知道它的存在還是有點必要的。
6 推導(dǎo)巨大的列表 - 不要這么干!
推導(dǎo)出1到100億之間的數(shù)字的平方,代碼如下:
nums?=?[i*i?for?i?in?range(1,10000000000)]
但是這段代碼很可能會卡死你的電腦,除非你的電腦是超級計算機。因為它要在內(nèi)存中做100億次計算,然后保存這100億個數(shù)字。
7 使用生成器
這種情況下,我們應(yīng)該使用推導(dǎo)生成器,用法很簡單:
把方括號改成圓括號就可以了
nums?=?(i*i?for?i?in?range(1,10000000000))
print(nums)
print(next(nums))
print(next(nums))
print(next(nums))
打印出來是一個生成器:
?at?0x7fa0b422feb0>
1
4
9
這是一個生成器,它不會一次性生成100億個數(shù)字,只有調(diào)用next()的時候,它才會生成一個新的,返回給你。也就是說,同一個時間,只保存一個數(shù)字。
8 推導(dǎo)字典
推導(dǎo)字典的方式和推導(dǎo)列表很相似,只不過:
使用大括號 使用鍵值對
推導(dǎo)一個包含數(shù)字和數(shù)字平方組成的字典,結(jié)果是這樣的:
{1:?1,?2:?4,?3:?9,?...,?100:?10000}
代碼:
nums_dict?=?{n:n*n?for?n?in?range(1,101)}
print(nums_dict)
反過來,平方在前面,數(shù)字在后面:
nums_dict?=?{n*n:n?for?n?in?range(1,101)}
print(nums_dict)
給下面的字典按照分?jǐn)?shù)排序:
{'麥?zhǔn)?:59,?'張三':87,?'FGA':78,?'石石':100,?'莫名':90}
排序結(jié)果:
{'石石':?100,?'莫名':?90,?'張三':?87,?'FGA':?78,?'麥?zhǔn)?:?59}
代碼:
scores?=?{'麥?zhǔn)?:59,?'張三':87,?'FGA':78,?'石石':100,?'莫名':90}
sored_scores?=?{item[0]:item[1]?for?item?in?sorted(scores.items(),?key=lambda?item:item[1],?reverse=True)}
print(sored_scores)
先把字典scores變成一個元組列表:scores.items() 用sorted函數(shù)給元組列表排序:sorted(scores.items(), key=lambda item:item[1], reverse=True) 排序過程用lambda指定使用元組的第二列排序:key=lambda item:item[1]。默認(rèn)是是第一列。 指定倒著排序,也就是分?jǐn)?shù)高的在前面:reverse=True 使用推導(dǎo)式,把排好序的元組列表,生成一個新的排好序的字典:{item[0]:item[1] for item in ... }
9 推導(dǎo)集合Set
推導(dǎo)集合的方式和列表是一樣的,區(qū)別在于:
使用大括號,類似于推導(dǎo)字典,但它是單個元素,而不是鍵值對。 集合會自動過濾掉重復(fù)的元素。
下面的名字列表,去掉前后空格后去掉重復(fù)的名字:
[?'麥?zhǔn)?,?'張三',?'?麥?zhǔn)?',?'FGA?',?'張小三',?'FGA',?'石石','?莫名','莫名'?]
推導(dǎo)結(jié)果:
{'石石',?'FGA',?'張小三',?'莫名',?'張三',?'麥?zhǔn)?}
代碼:
names?=?[?'麥?zhǔn)?,?'張三',?'?麥?zhǔn)?',?'FGA?',?'張小三',?'FGA',?'石石','?莫名','莫名'?]
new_names?=?{n.strip()?for?n?in?names}
print(new_names)-END-
掃碼添加早小起
1.?回復(fù)「進群」進入Python技術(shù)交流群
2. 回復(fù)「Python」獲得Python技術(shù)圖書
3. 回復(fù)「習(xí)題」領(lǐng)取Python數(shù)據(jù)處理200題
