Python基礎之 推導式 與 匿名函數

推導式

推導式( 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 的列表推導式改成生成器表達式就好了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章