推導式
推導式( comprehensions ),又稱爲解析式,是 Python 中的一種獨有特性。推導式是可以從一個數據序列構建另一個新的數據序列的結構體。 共有三種推導式:
· 列表推導式
· 字典推導式
· 集合推導式
推導式具有固定的格式,下面以列表推導式爲例(也適用於其他推導式):
variable = [out_exp_res for out_exp in input_list if out_exp == 2]
out_exp_res :列表生成元素表達式,可以是有返回值的函數。
for out_exp in input_list :迭代input_list將out_exp傳入out_exp_res表達式中。
if out_exp == 2 : 根據條件過濾哪些值可以。
根據推導式的固定格式,下面分別給出三種數據類型的推導式實例。
列表推導式
1. 找出20以內的所有偶數
even_num = [i for i in range(20) if i % 2 == 0]
print(even_num) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
2. 找出10000以內的完全數的平方
完全數是所有真因子(除了它本身的所有約數)之和等於它本身的數。例如6, 1+2+3 = 6。 它的平方就是36。
def is_prefect_number(n):
cnt = 0
for i in range(1, n):
if n % i == 0:
cnt += i
if cnt == n:
return True
def squared(n):
return n * n
square_prefect_num = [squared(i) for i in range(1, 10000) if is_prefect_number(i)]
print(square_prefect_num) # [36, 784, 246016, 66064384]
3. 將名單的嵌套列表中含有兩個 L(不區分大小寫)的名字找出來
names = [['Smith', 'Johnson', ' Williams', 'Jones'], ['Brown', 'Allen',
'Lee', 'Hall'], ['Anderson', 'King', 'Collins', 'Miller', 'Taylor'], ['Phillips', 'Thompson']]
L_in_name = [name for lst in names for name in lst if name.lower().count('l') == 2]
print(L_in_name) # [' Williams', 'Allen', 'Hall', 'Collins', 'Miller', 'Phillips']
字典推導式
1. 將字典的 key 與 value 對調
dic = {'a': 1, 'b': 2}
dic_ver = {dic[k]: k for k in dic}
print(dic_ver) # {1: 'a', 2: 'b'}
2. 合併大小寫對應的 value,並將 key 統一小寫
dic = {'a': 3, 'b': 7, 'A': 9, 'c': 14, 'B': 1}
dic_merge = {k.lower(): dic.get(k.lower(), 0) + dic.get(k.upper(), 0) for k in dic}
print(dic_merge) # {'a': 12, 'b': 8, 'c': 14}
集合推導式
集合推導式就是列表推導式的 [] 改成 {} ,只是集合推導式自帶去重效果。
1. 求列表中所有數的平方
set_square = {i**2 for i in [-2, -1, 1, 2, 3]}
print(set_square)
匿名函數
匿名函數是爲了解決功能簡單的需求而設計的一句話函數,在一些特定的情況下使用會更加簡潔方便。
def squared(n):
return n**2
print(squared(2)) # 4
上面是常見的求一個數的平方的函數寫法,我們把它換成匿名函數。
squared = lambda n: n**2
print(squared(4)) # 4
觀察可得知匿名函數的固定格式爲:
函數名 = lambda 參數: 返回值
注:
① 參數可以擁有多個,多個參數之間用逗號隔開;
② 匿名函數無論邏輯複雜程度都只能寫一行,函數的返回值就是這一行的運行結果。 返回值可以是任意數據類型;
③ 匿名函數和普通函數一樣可以通過 函數名(參數) 的方式調用。
通過上面的分析總結,我們知道匿名函數並不是真的匿名,它也是使用函數名來調用。 它的作用只是這樣了嗎? 這樣它存在有什麼意義呢? 我們直接用函數不就好了?
其實匿名函數大顯身手的地方並不是這裏,它在和其他功能函數合作的時候就可以真正的匿名了。例如配合 Python 中的內置函數使用:
1. 配合 map,將兩個列表對應位置相加
ret = map(lambda x, y: x+y, [1, 3, 2, 7], [5, 9, 0, 1])
print(list(ret)) # [6, 12, 2, 8] ret是一個map對象,是一個迭代器,需要將它轉化爲列表
2. 使用 sorted,將字典按照 value 排序
dic = {'A': 2, 'B': 4, 'C': 1, 'D': 9, 'E': 7}
# 將字典轉化爲一個可迭代對象,每一個item就是一個的元祖,再按照元祖的第二個值(也就是字典的value)進行排序
list_dic = sorted(dic.items(), key=lambda item: item[1])
print(list_dic)
3. 現有兩個元祖 ((‘a’), (‘b’)), ((‘c’), (d)),使用匿名函數將其轉化爲 [{‘a’:‘c’}, {‘b’:‘d’}]。
t1 = (('a'), ('b'))
t2 = (('c'), ('d'))
# 方法1
fuc = lambda x, y: [{i: j} for i, j in zip(x, y)]
print(fuc(t1, t2))
# 方法2
ret = list(map(lambda t: {t[0]: t[1]}, zip(t1, t2)))
print(ret)
# 方法3(不適用匿名函數,使用列表推導式)
ret = [{i: j} for i, j in zip(t1, t2)]
print(ret)
4. 有趣的刁鑽小題
def multipliers():
return [lambda x:i*x for i in range(4)]
print([m(2) for m in multipliers()])
請問這段代碼的運行結果是什麼,怎麼樣才能得到我們想要的結果?
首先揭開謎底運行結果是[6, 6, 6, 6]
,爲什麼呢? 請看:
def multipliers():
return [lambda x:i*x for i in range(4)] # 1.列表推導式,這裏面存放的是四個函數地址,函數爲lambda x:i*x
# 2.那麼實際上這裏就是: return [lambda x: i*x的地址, lambda x: i*x的地址, lambda x: i*x的地址, lambda x: i*x的地址]
print([m(2) for m in multipliers()]) # 3.那麼這裏就變成了 for m in [lambda x: i*x的地址, lambda x: i*x的地址, lambda x: i*x的地址, lambda x: i*x的地址]
# 4.每一個m都是相同的函數名,傳入參數2,這裏就有了
# [lambda 2: i*2, lambda 2: i*2, lambda 2: i*2, lambda 2: i*2]
# 此時開始調用lambda函數,找到i的內存地址,發現i==3
那麼我們想要結果爲[0, 2, 4 6]
,該怎麼做?
將函數中 return 的列表推導式改成生成器表達式就好了。