Python lambda 函數深度總結

數據分析那些事
11 min readJul 5, 2022

--

文章來源於:公眾號尤爾小屋

今天我們來學習 Python 中的 lambda 函數,並探討使用它的優點和侷限性

什麼是 Lambda 函數

lambda 函數是一個匿名函數(即,沒有名稱定義),它可以接受任意數量的參數,但與普通函數不同,它只計算並返回一個表達式

Python 中的 lambda 函數使用以下語法表達:

lambda 參數:表達式

lambda 函數包括三個元素:

關鍵字 lambda:與普通函數中 def 類似

參數:支持傳遞位置和關鍵字參數,與普通函數一樣

正文:處理定參數的表達式

需要注意的是,普通函數不同,這裏不需要用括號將 lambda 函數的參數括起來,如果 lambda 函數有兩個或更多參數,我們用逗號列出它們

我們使用 lambda 函數只計算一個短表達式(理想情況下,單行)並且只計算一次,這意味着我們以後不會再複用這個函數。通常來說我們會將 lambda 函數作爲參數傳遞給高階函數(接受其他函數作爲參數的函數),例如 Python 內置函數,如 filter()、map() 或 reduce()等

Python 中的 Lambda 函數如何工作

讓我們看一個簡單的 lambda 函數示例:

lambda x: x + 1

Output:

<function __main__.<lambda>(x)>

上面的 lambda 函數接受一個參數,將其遞增 1,然後返回結果

它是以下帶有 def 和 return 關鍵字的普通函數的更簡單版本:

def increment_by_one(x):

return x + 1

到目前我們的 lambda 函數 lambda x: x + 1 只創建一個函數對象,不返回任何內容,這是因爲我們沒有爲其參數 x 提供任何值(參數)。讓我們先分配一個變量,將它傳遞給 lambda 函數,看看這次我們得到了什麼:

a = 2

print(lambda x: a + 1)

Output:

<function <lambda> at 0x00000250CB0A5820>

我們的 lambda 函數沒有像我們預期的那樣返回 3,而是返回了函數對象本身及其內存位置,可以看出這不是調用 lambda 函數的正確方法。要將參數傳遞給 lambda 函數,執行它並返回結果,我們應該使用以下語法:

(lambda x: x + 1)(2)

Output:

3

雖然我們的 lambda 函數的參數沒有用括號括起來,但當我們調用它時,我們會在 lambda 函數的整個構造以及我們傳遞給它的參數周圍添加括號

上面代碼中要注意的另一件事是,使用 lambda 函數,我們可以在創建函數後立即執行該函數並接收結果。這就是所謂的立即調用函數執行(或 IIFE)

我們可以創建一個帶有多個參數的 lambda 函數,在這種情況下,我們用逗號分隔函數定義中的參數。當我們執行這樣一個 lambda 函數時,我們以相同的順序列出相應的參數,並用逗號分隔它們:

(lambda x, y, z: x + y + z)(3, 8, 1)

Output:

12

也可以使用 lambda 函數來執行條件操作。下面是一個簡單 if-else 函數的 lambda 模擬:

print((lambda x: x if(x > 10) else 10)(5))

print((lambda x: x if(x > 10) else 10)(12))

Output:

10

12

如果存在多個條件(if-elif-…-else),我們必須嵌套它們:

(lambda x: x * 10 if x > 10 else (x * 5 if x < 5 else x))(11)

Output:

110

但是上面的寫法,又令代碼變得難以閱讀

在這種情況下,具有 if-elif-…-else 條件集的普通函數將是比 lambda 函數更好的選擇。實際上,我們可以通過以下方式編寫上面示例中的 lambda 函數:

def check_conditions(x):

if x > 10:

return x * 10

elif x < 5:

return x * 5

else:

return x

check_conditions(11)

Output:

110

儘管上面的函數比相應的 lambda 函數增加了更多行,但它更容易閱讀

我們可以將 lambda 函數分配給一個變量,然後將該變量作爲普通函數調用:

increment = lambda x: x + 1

increment(2)

Output:

3

但是根據 Python 代碼的 PEP 8 樣式規則,這是一種不好的做法

賦值語句的使用消除了 lambda 表達式相對於顯式 def 語句所能提供的唯一好處(即,它可以嵌入到更大的表達式中)

因此如果我們確實需要存儲一個函數以供進一步使用,我們最好定義一個等效的普通函數,而不是將 lambda 函數分配給變量

Lambda 函數在 Python 中的應用

帶有 filter() 函數的 Lambda

Python 中的 filter() 函數需要兩個參數:

定義過濾條件的函數

函數在其上運行的可迭代對象

運行該函數,我們得到一個過濾器對象:

lst = [33, 3, 22, 2, 11, 1]

filter(lambda x: x > 10, lst)

Output:

<filter at 0x250cb090520>

爲了從過濾器對象中獲取一個新的迭代器,並且原始迭代器中的所有項都滿足預定義的條件,我們需要將過濾器對象傳遞給 Python 標準庫的相應函數:list()、tuple()、set ()、frozenset() 或 sorted()(返回排序列表)

讓我們過濾一個數字列表,只選擇大於 10 的數字並返回一個按升序排序的列表:

lst = [33, 3, 22, 2, 11, 1]

sorted(filter(lambda x: x > 10, lst))

Output:

[11, 22, 33]

我們不必創建與原始對象相同類型的新可迭代對象,此外我們可以將此操作的結果存儲在一個變量中:

lst = [33, 3, 22, 2, 11, 1]

tpl = tuple(filter(lambda x: x > 10, lst))

tpl

Output:

(33, 22, 11)

帶有 map() 函數的 Lambda

我們使用 Python 中的 map() 函數對可迭代的每個項目執行特定操作。它的語法與 filter() 相同:一個要執行的函數和一個該函數適用的可迭代對象。

map() 函數返回一個 map 對象,我們可以通過將該對象傳遞給相應的 Python 函數來從中獲取一個新的迭代:list()、tuple()、set()、frozenset() 或 sorted()

與 filter() 函數一樣,我們可以從 map 對象中提取與原始類型不同類型的可迭代對象,並將其分配給變量。

下面是使用 map() 函數將列表中的每個項目乘以 10 並將映射值作爲分配給變量 tpl 的元組輸出的示例:

lst = [1, 2, 3, 4, 5]

print(map(lambda x: x * 10, lst))

tpl = tuple(map(lambda x: x * 10, lst))

tpl

Output:

<map object at 0x00000250CB0D5F40>

(10, 20, 30, 40, 50)

map() 和 filter() 函數之間的一個重要區別是第一個函數總是返回與原始函數相同長度的迭代。因此由於 pandas Series 對象也是可迭代的,我們可以在 DataFrame 列上應用 map() 函數來創建一個新列:

import pandas as pd

df = pd.DataFrame({‘col1’: [1, 2, 3, 4, 5], ‘col2’: [0, 0, 0, 0, 0]})

print(df)

df[‘col3’] = df[‘col1’].map(lambda x: x * 10)

df

Output:

當然要在上述情況下獲得相同的結果,也可以使用 apply() 函數:

df[‘col3’] = df[‘col1’].apply(lambda x: x * 10)

df

Output:

我們還可以根據某些條件爲另一列創建一個新的 DataFrame 列,對於下面的代碼,我們可以互換使用 map() 或 apply() 函數:

df[‘col4’] = df[‘col3’].map(lambda x: 30 if x < 30 else x)

df

Output:

帶有 reduce() 函數的 Lambda

reduce() 函數與 functools Python 模塊相關,它的工作方式如下:

對可迭代對象的前兩項進行操作並保存結果

對保存的結果和可迭代的下一項進行操作

以這種方式在值對上進行,直到所有項目使用可迭代的

該函數與前兩個函數具有相同的兩個參數:一個函數和一個可迭代對象。但是與前面的函數不同的是,這個函數不需要傳遞給任何其他函數,直接返回結果標量值:

from functools import reduce

lst = [1, 2, 3, 4, 5]

reduce(lambda x, y: x + y, lst)

Output:

15

上面的代碼展示了我們使用 reduce() 函數計算列表總和時的作用

需要注意的是,reduce() 函數總是需要一個帶有兩個參數的 lambda 函數,而且我們必須首先從 functools Python 模塊中導入它

Python 中 Lambda 函數的優缺點

優點

它是評估單個表達式的理想選擇,應該只評估一次

它可以在定義後立即調用

與相應的普通語法相比,它的語法更緊湊

它可以作爲參數傳遞給高階函數,例如 filter()、map() 和 reduce()

缺點

它不能執行多個表達式

它很容易變得麻煩,可讀性差,例如當它包括一個 if-elif-…-else 循環

它不能包含任何變量賦值(例如,lambda x: x=0 將拋出一個語法錯誤)

我們不能爲 lambda 函數提供文檔字符串

總結

總而言之,我們已經詳細討論了在 Python 中定義和使用 lambda 函數的許多方面:

lambda 函數與普通 Python 函數有何不同

Python 中 lambda 函數的語法和剖析

何時使用 lambda 函數

lambda 函數的工作原理

如何調用 lambda 函數

調用函數執行(IIFE)的定義

如何使用 lambda 函數執行條件操作,如何嵌套多個條件,以及爲什麼我們應該避免它

爲什麼我們應該避免將 lambda 函數分配給變量

如何將 lambda 函數與 filter() 函數一起使用

如何將 lambda 函數與 map() 函數一起使用

我們如何在 pandas DataFrame 中使用

帶有傳遞給它的 lambda 函數的 map() 函數 — 以及在這種情況下使用的替代功能

如何將 lambda 函數與 reduce() 函數一起使用

在普通 Python 上使用 lambda 函數的優缺點

原文地址:https://mp.weixin.qq.com/s/Xj9Tu05I65JckP0dN5r-3Q

※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※

我是「數據分析那些事」。常年分享數據分析乾貨,不定期分享好用的職場技能工具。各位也可以關注我的Facebook,按讚我的臉書並私訊「10」,送你十週入門數據分析電子書唷!期待你與我互動起來~

文章推薦

餅圖變形記,肝了3000字,收藏就是學會!

MySQL必須掌握4種語言!

太實用了!4種方法教你輕鬆製作互動式儀表板!

跟資料打交道的人都得會的這8種資料模型,滿足工作中95%的需求

妙呀!一行Python程式碼

回顧十週入門數據分析系列文:

關注數據君的臉書:

我是「數據分析那些事」。常年分享數據分析乾貨,不定期分享好用的職場技能工具。按贊我的臉書,會有豐富資料包贈送唷!

--

--

數據分析那些事
數據分析那些事

Written by 數據分析那些事

這是一個專注於數據分析職場的內容部落格,聚焦一批數據分析愛好者,在這裡,我會分享數據分析相關知識點推送、(工具/書籍)等推薦、職場心得、熱點資訊剖析以及資源大盤點,希望同樣熱愛數據的我們一同進步! 臉書會有更多互動喔:https://www.facebook.com/shujvfenxi/

No responses yet