如果你剛開始使用 Python,那么理解什么是 lambda 可能會(huì)有些混亂。 lambda 也稱為匿名函數(shù),這是因?yàn)?lambda 沒有名稱。要在 Python 中定義 lambda,你可以使用關(guān)鍵字 lambda 后跟一個(gè)或多個(gè)參數(shù)、一個(gè)冒號(hào) (:) 和一個(gè)表達(dá)式。 我們將從一個(gè)簡(jiǎn)單的 lambda 函數(shù)示例開始,以熟悉其語(yǔ)法,然后我們將了解 Python lambda 函數(shù)如何適用于不同的場(chǎng)景。 如何在 Python 中使用 Lambda讓我們從 lambda 函數(shù)的語(yǔ)法開始。 lambda 函數(shù)以lambda關(guān)鍵字開頭,后跟逗號(hào)分隔的參數(shù)列表。下一個(gè)元素是一個(gè)冒號(hào)(:),后跟一個(gè)表達(dá)式。 lambda <argument(s)> : <expression> 如你所見,可以在一行中定義一個(gè) lambda 函數(shù)。 讓我們看一個(gè)非常簡(jiǎn)單的 lambda,它將數(shù)字 x(參數(shù))乘以 2: lambda x : 2*x 運(yùn)行返回了一個(gè)函數(shù)對(duì)象。有趣的是,當(dāng)我定義一個(gè) lambda 時(shí),我不需要 return 語(yǔ)句作為表達(dá)式的一部分。 如果我在表達(dá)式中包含 return 語(yǔ)句會(huì)怎樣? 我們收到語(yǔ)法錯(cuò)誤。所以,不需要在 lambda 中包含 return 。 如何在 Python 中調(diào)用 Lambda 函數(shù)我們已經(jīng)了解了如何定義 lambda,但我們?nèi)绾握{(diào)用它呢? 首先,我們將在不將函數(shù)對(duì)象分配給變量的情況下執(zhí)行此操作。為此,我們只需要使用括號(hào)。 (lambda x : 2*x)(2) 我們將用括號(hào)將 lambda 表達(dá)式括起來(lái),然后用括號(hào)括起我們要傳遞給 lambda 的參數(shù)。 這是我們運(yùn)行時(shí)的輸出: 我們還有另一種選擇。我們可以將lambda函數(shù)返回的函數(shù)對(duì)象賦值給一個(gè)變量,然后使用變量名調(diào)用函數(shù)。 multiply = lambda x : 2*xmultiply(2) 這是我們運(yùn)行時(shí)的輸出: 將多個(gè)參數(shù)傳遞給 Lambda 函數(shù)在前面的部分中,我們了解了如何定義和執(zhí)行 lambda 函數(shù)。 我們還看到 lambda 可以有一個(gè)或多個(gè)參數(shù),讓我們看一個(gè)有兩個(gè)參數(shù)的例子。 創(chuàng)建一個(gè)將參數(shù) x 和 y 相乘的 lambda: (lambda x, y : x*y)(2,3) 這是我們運(yùn)行時(shí)的輸出: lambda 是一個(gè)IIFE(立即調(diào)用的函數(shù)表達(dá)式)。它基本上是一種表示 lambda 函數(shù)在定義后立即執(zhí)行的方式。 Lambda 函數(shù)和常規(guī)函數(shù)之間的區(qū)別在繼續(xù)研究如何在 Python 程序中使用 lambda 之前,了解常規(guī) Python 函數(shù)和 lambda 之間的關(guān)系很重要。 讓我們以相乘的例子為例: lambda x, y : x*y 我們也可以使用def關(guān)鍵字將其編寫為常規(guī)函數(shù): def multiply(x, y): return x*y 與 lambda 形式相比,你會(huì)立即注意到三個(gè)不同之處:
將我們的 lambda 函數(shù)分配給一個(gè)變量是可選的 multiply_lambda = lambda x, y : x*y 讓我們比較一下這兩個(gè)函數(shù)的對(duì)象: def multiply(x, y): return x*y multiply_lambda = lambda x, y : x*yprint(multiply)print(multiply_lambda) 從上面的圖我們可以看到一個(gè)區(qū)別:使用 def 關(guān)鍵字定義的函數(shù)由名稱“multiply”標(biāo)識(shí),而 lambda 函數(shù)由通用 <lambda> 標(biāo)簽標(biāo)識(shí)。 讓我們看看type() 函數(shù)在應(yīng)用于這兩個(gè)函數(shù)時(shí)返回的內(nèi)容: 所以,這兩個(gè)函數(shù)的類型是一樣的。 可以在 Python Lambda 中使用 If Else 嗎?lambda x: x if x > 2 else 2*x 如果 x 大于 2,則此 lambda 應(yīng)返回 x,否則應(yīng)返回 x 乘以 2。 測(cè)試一下我們的功能: 同時(shí)你可以看到,如果我們讓 lambda 表達(dá)式變得越來(lái)越復(fù)雜,我們的代碼會(huì)變得更難閱讀。 如何用 Lambda 和 Map 替換 For 循環(huán)在本節(jié)中,我們將看到 lambda 在應(yīng)用于像Python 列表這樣的可迭代對(duì)象時(shí)如何變得非常強(qiáng)大。 讓我們從一個(gè)標(biāo)準(zhǔn)的 Python for 循環(huán)開始,循環(huán)遍歷字符串列表的所有元素并創(chuàng)建一個(gè)新列表,其中所有元素都是大寫的。 names = ['Jack', 'Elio', 'Helen']names_result = []for name in names: names_result.append(name.upper()) 這是輸出: 現(xiàn)在我們將編寫相同的代碼,但使用 lambda。為此,我們還將使用一個(gè)名為map的 Python 內(nèi)置函數(shù),其語(yǔ)法如下: map(function, iterable, ...) map 函數(shù)將另一個(gè)函數(shù)作為第一個(gè)參數(shù),然后是一個(gè)可迭代列表。在這個(gè)具體的例子中,我們只有一個(gè)可迭代對(duì)象,即名字列表。 將另一個(gè)函數(shù)作為參數(shù)的函數(shù)稱為高階函數(shù)。 這聽起來(lái)可能很復(fù)雜,這個(gè)例子將幫助你理解它是如何工作的。 那么,map函數(shù)有什么作用呢? map 函數(shù)返回一個(gè)可迭代對(duì)象,它是作為第一個(gè)參數(shù)傳遞給可迭代對(duì)象的每個(gè)元素的函數(shù)的結(jié)果。 在我們的場(chǎng)景中,我們將作為第一個(gè)參數(shù)傳遞的函數(shù)將是一個(gè) lambda 函數(shù),它將其參數(shù)轉(zhuǎn)換為大寫格式。作為可迭代的,我們將傳遞我們的list。 map(lambda x: x.upper(), names) 上面執(zhí)行會(huì)返回一個(gè)map對(duì)象。我們?cè)鯓硬拍苋』亓斜砟兀?/p> 我們可以將map對(duì)象轉(zhuǎn)換為列表 list(map(lambda x: x.upper(), names)) 很明顯,與我們使用 for 循環(huán)的代碼相比,使用 map 和 lambda 可以使這段代碼更加簡(jiǎn)潔。 將 Lambda 函數(shù)與字典結(jié)合使用我想嘗試使用 lambda 函數(shù)從字典列表中提取特定字段。 這是很多場(chǎng)景都可以應(yīng)用的東西,下面是一個(gè)列表里面包含字典。 people = [{'firstname':'John', 'lastname':'Ross'}, {'firstname':'Mark', 'lastname':'Green'}] 我又一次可以將 map 內(nèi)置函數(shù)與 lambda 函數(shù)一起使用。 lambda 函數(shù)將一個(gè)字典作為參數(shù)并返回 firstname 鍵的值。 lambda x : x['firstname'] 完整的表達(dá)式是: firstnames = list(map(lambda x : x['firstname'], people)) 運(yùn)行輸出: 將 Lambda 傳遞給過(guò)濾器內(nèi)置函數(shù)另一個(gè)可以與 lambda 一起使用的 Python 內(nèi)置函數(shù)是filter 函數(shù)。 下面你可以看到它的語(yǔ)法需要一個(gè)函數(shù)和一個(gè)可迭代對(duì)象: filter(function, iterable) 這里的想法是創(chuàng)建一個(gè)表達(dá)式,給定一個(gè)列表返回一個(gè)新列表,其元素匹配 lambda 函數(shù)定義的特定條件。 例如,給定一個(gè)數(shù)字列表,我想返回一個(gè)只包含負(fù)數(shù)的列表。 這是我們將使用的 lambda 函數(shù): lambda x : x < 0 讓我們嘗試執(zhí)行此 lambda 并將幾個(gè)數(shù)字傳遞給它,以便清楚 lambda 返回的內(nèi)容。 (lambda x : x < 0)(-1) # True(lambda x : x < 0)(3) # False 我們的 lambda 返回一個(gè)布爾值:
現(xiàn)在,讓我們將此 lambda 應(yīng)用于過(guò)濾器函數(shù): numbers = [1, 3, -1, -4, -5, -35, 67]negative_numbers = list(filter(lambda x : x < 0, numbers))print(negative_numbers) 我們得到了預(yù)期的結(jié)果,一個(gè)包含所有負(fù)數(shù)的列表。 Reduce 和 Lambda 如何與列表一起使用另一個(gè)常見的 Python 內(nèi)置函數(shù)是屬于functools 模塊的reduce 函數(shù)。 reduce(function, iterable[, initializer]) reduce 函數(shù)有什么作用?,reduce函數(shù)會(huì)對(duì)參數(shù)迭代器中的元素進(jìn)行積累。 ruduce函數(shù)的定義如下: functools.reduce(function, iterable[, initializer]) 為了在實(shí)踐中理解它,我們將應(yīng)用一個(gè)簡(jiǎn)單的 lambda 來(lái)計(jì)算兩個(gè)數(shù)字的總和到數(shù)字列表: from functools import reducereduce(lambda x,y: x+y, [3, 7, 10, 12, 5]) 運(yùn)行輸出: 讓我們看看我們是否也可以使用 reduce 函數(shù)來(lái)連接列表中的字符串: from functools import reducereduce(lambda x,y: x + ' ' + y, ['This', 'is', 'a', 'tutorial', 'about', 'Python', 'lambdas']) 運(yùn)行輸出: 應(yīng)用于類的 Lambda 函數(shù)考慮到 lambda 可以用來(lái)代替常規(guī)的 Python 函數(shù),我們可以將 lambda 用作類方法嗎? 我將定義一個(gè)名為 Gorilla 的類,它包含一個(gè)構(gòu)造函數(shù)和打印消息的運(yùn)行方法: class Gorilla: def __init__(self, name, age, weight): self.name = name self.age = age self.weight = weight def run(self): print('{} starts running!'.format(self.name)) 然后我創(chuàng)建了這個(gè)類的一個(gè)名為 Spartacus 的實(shí)例并在其上執(zhí)行 run 方法: Spartacus = Gorilla('Spartacus', 35, 150)Spartacus.run() 輸出是: 現(xiàn)在,讓我們用 lambda 函數(shù)替換 run 方法: class Gorilla: def __init__(self, name, age, weight): self.name = name self.age = age self.weight = weight run = lambda self: print('{} starts running!'.format(self.name)) 在 Gorilla 類的實(shí)例上再次執(zhí)行 run 方法,會(huì)看到輸出消息完全相同。 將 Lambda 與排序函數(shù)一起使用sorted 內(nèi)置函數(shù)從可迭代對(duì)象返回一個(gè)排序列表。 讓我們看一個(gè)簡(jiǎn)單的例子,我們將對(duì)包含一些行星名稱的列表進(jìn)行排序: planets = ['saturn', 'earth', 'mars', 'jupiter'] # 排序函數(shù)按字母順序?qū)α斜磉M(jìn)行排序sorted(planets) 運(yùn)行輸出: 現(xiàn)在,假設(shè)我們要根據(jù)不同的標(biāo)準(zhǔn)對(duì)列表進(jìn)行排序,例如每個(gè)單詞的長(zhǎng)度。 為此,我們可以使用額外的參數(shù)鍵,它允許在進(jìn)行任何比較之前提供一個(gè)應(yīng)用于每個(gè)元素的函數(shù)。 sorted(planets, key=len) # ['mars', 'earth', 'saturn', 'jupiter'] 在這種情況下,我們使用了 len() 內(nèi)置函數(shù),這就是行星從最短到最長(zhǎng)排序的原因。 那么,lambda 在哪里適合所有這些? Lambda 是函數(shù),因此它們可以與 key 參數(shù)一起使用。 例如,假設(shè)我想根據(jù)每個(gè)行星的第三個(gè)字母對(duì)我的列表進(jìn)行排序。 sorted(planets, key=lambda p: p[2]) #['jupiter', 'earth', 'mars', 'saturn'] 如果我想根據(jù)特定屬性的值對(duì)字典列表進(jìn)行排序怎么辦? people = [{'firstname':'John', 'lastname':'Ross'}, {'firstname':'Mark', 'lastname':'Green'}]sorted(people, key=lambda x: x['lastname']) 在此示例中,我們根據(jù)姓氏鍵的值對(duì)字典列表進(jìn)行了排序。 運(yùn)行輸出: Python Lambda 和錯(cuò)誤處理在我們查看 lambda 和常規(guī)函數(shù)之間區(qū)別的部分中,我們看到了以下內(nèi)容: >>> multiply<function multiply at 0x101451d40>>>> multiply_lambda<function <lambda> at 0x1014227a0> 其中 multiply 是一個(gè)常規(guī)函數(shù),multiply_lambda 是一個(gè) lambda 函數(shù)。 如你所見,常規(guī)函數(shù)的函數(shù)對(duì)象由名稱標(biāo)識(shí),而 lambda 函數(shù)對(duì)象由通用 <lambda> 名稱標(biāo)識(shí)。 這也使得 lambda 函數(shù)的錯(cuò)誤處理變得更加棘手,因?yàn)?Python 回溯不包括發(fā)生錯(cuò)誤的函數(shù)的名稱。 讓我們創(chuàng)建一個(gè)常規(guī)函數(shù)并向其傳遞會(huì)導(dǎo)致 Python 解釋器引發(fā)異常的參數(shù): def calculate_sum(x, y): return x+yprint(calculate_sum(5, 'Not_a_number')) 當(dāng)我在 Python shell 中運(yùn)行此代碼時(shí),出現(xiàn)以下錯(cuò)誤: >>> def calculate_sum(x, y):... return x+y... >>> print(calculate_sum(5, 'Not_a_number'))Traceback (most recent call last): File '<stdin>', line 1, in <module> File '<stdin>', line 2, in calculate_sumTypeError: unsupported operand type(s) for +: 'int' and 'str' 從回溯中我們可以清楚地看到錯(cuò)誤發(fā)生在 calculate_sum 函數(shù)的第 2 行。 現(xiàn)在,讓我們用 lambda 替換這個(gè)函數(shù): calculate_sum = lambda x, y: x+yprint(calculate_sum(5, 'Not_a_number')) 輸出是: >>> calculate_sum = lambda x,y: x+y>>> print(calculate_sum(5, 'Not_a_number'))Traceback (most recent call last): File '<stdin>', line 1, in <module> File '<stdin>', line 1, in <lambda>TypeError: unsupported operand type(s) for +: 'int' and 'str' 異常類型和錯(cuò)誤消息是一樣的,但是這次回溯告訴我們函數(shù) <lambda> 的第 1 行發(fā)生了錯(cuò)誤。想象一下,如果要你必須在 10,000 行代碼中找到正確的行是不是大海撈針。這就是為啥盡可能使用常規(guī)函數(shù)而不是 lambda 函數(shù)的另一個(gè)原因。 將可變參數(shù)列表傳遞給 Python Lambda在本節(jié)中,我們將了解如何向 Python lambda 提供可變參數(shù)列表。 要將可變數(shù)量的參數(shù)傳遞給 lambda,我們可以像使用常規(guī)函數(shù)一樣使用*args : lambda *args: max(args))(5, 3, 4, 10, 24) 當(dāng)我們運(yùn)行它時(shí),我們得到傳遞給 lambda 的參數(shù)之間的最大值: >>> (lambda *args: max(args))(5, 3, 4, 10, 24)24 我們不一定要使用關(guān)鍵字 args。重要的是 args 之前的 * 在 Python 中代表可變數(shù)量的參數(shù)。 讓我們通過(guò)用數(shù)字替換 args 來(lái)確認(rèn)是否是這種情況: >>> (lambda *numbers: max(numbers))(5, 3, 4, 10, 24)24 Lambda 函數(shù)的更多示例如果你想在 Python 程序中使用 lambda,這些示例應(yīng)該會(huì)給你更多的想法。 給定一個(gè) Linux 命令列表,只返回以字母“c”開頭的命令: >>> commands = ['ls', 'cat', 'find', 'echo', 'top', 'curl']>>> list(filter(lambda cmd: cmd.startswith('c'), commands))['cat', 'curl'] 從帶空格的逗號(hào)分隔字符串返回一個(gè)列表,其中包含不帶空格的字符串中的每個(gè)單詞: >>> weekdays = 'monday , tuesday, wednesday,thursday, friday, saturday ,sunday'>>> list(map(lambda word: word.strip(), weekdays.split(',')))['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'] 使用 Python range 函數(shù)生成數(shù)字列表并返回大于四的數(shù)字: >>> list(filter(lambda x: x > 4, range(15)))[5, 6, 7, 8, 9, 10, 11, 12, 13, 14] 結(jié)論在本篇文章中,我們了解了什么是 Python lambda,以及如何定義和執(zhí)行它。 我們?yōu)g覽了帶有一個(gè)或多個(gè)參數(shù)的示例,我們還看到了 lambda 如何返回一個(gè)函數(shù)對(duì)象(不需要 return 語(yǔ)句)。 現(xiàn)在你知道 lambda 也稱為匿名函數(shù),因?yàn)楫?dāng)你定義它時(shí),你不會(huì)將它綁定到一個(gè)名稱。 此外,分析 Python 中常規(guī)函數(shù)和 lambda 函數(shù)之間的區(qū)別有助于我們更好地理解 lambda 的工作原理。 當(dāng)你的代碼中只需要一次時(shí),使用 lambda 函數(shù)是很常見的。如果你需要在代碼庫(kù)中多次調(diào)用的函數(shù),使用常規(guī)函數(shù)是避免代碼重復(fù)的更好方法。 永遠(yuǎn)記住編寫干凈的代碼是多么重要,任何人都可以快速理解的代碼,以防將來(lái)出現(xiàn)需要快速修復(fù)的錯(cuò)誤。 現(xiàn)在你可以在 lambda 表達(dá)式和常規(guī)函數(shù)之間做出選擇,做出正確的選擇! |
|
來(lái)自: 網(wǎng)摘文苑 > 《語(yǔ)言基礎(chǔ)》