自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一文帶您了解Python的函數(shù)式編程:理解lambda、map()、filter()和reduce()

開(kāi)發(fā) 前端
函數(shù)式編程是一種編程范式,其中主要的計(jì)算方法是純函數(shù)的求值。盡管 Python 主要不是函數(shù)式語(yǔ)言,但您仍然可以按照函數(shù)式編程原則編寫(xiě) Python。

函數(shù)式編程在數(shù)據(jù)處理領(lǐng)域中扮演著重要的角色,其優(yōu)勢(shì)在于能以簡(jiǎn)潔和直觀的方式處理和轉(zhuǎn)換數(shù)據(jù)。通過(guò)將數(shù)據(jù)轉(zhuǎn)換操作封裝在純函數(shù)中,函數(shù)式編程避免了副作用和可變狀態(tài),提升了代碼的可維護(hù)性和可讀性。在處理數(shù)據(jù)時(shí),函數(shù)式編程提供了強(qiáng)大的工具,如 lambda、map()、filter() 和 reduce(),這些工具允許開(kāi)發(fā)者高效地應(yīng)用操作、篩選和歸約數(shù)據(jù)集合。利用這些函數(shù),數(shù)據(jù)處理可以變得更加簡(jiǎn)潔、模塊化。這種編程范式不僅有助于編寫(xiě)更清晰的代碼,還能幫助開(kāi)發(fā)者應(yīng)對(duì)復(fù)雜的數(shù)據(jù)處理任務(wù),實(shí)現(xiàn)更高效的數(shù)據(jù)流轉(zhuǎn)和分析。

什么是函數(shù)式編程?

純函數(shù)是指輸出值完全由輸入值決定,并且沒(méi)有任何可觀察的副作用的函數(shù)。在函數(shù)式編程中,程序主要由純函數(shù)的計(jì)算組成。計(jì)算通過(guò)嵌套或組合的函數(shù)調(diào)用進(jìn)行,而不會(huì)改變狀態(tài)或可變數(shù)據(jù)。

函數(shù)式編程范式之所以受歡迎,是因?yàn)樗鄬?duì)于其他編程范式有幾個(gè)優(yōu)勢(shì)。函數(shù)式代碼具有以下特點(diǎn):

  • 高級(jí)抽象:您描述的是想要的結(jié)果,而不是明確指定如何一步步達(dá)成這個(gè)結(jié)果。單個(gè)語(yǔ)句通常簡(jiǎn)潔但功能強(qiáng)大。
  • 透明性:純函數(shù)的行為可以通過(guò)其輸入和輸出來(lái)描述,而無(wú)需依賴中間值。這消除了副作用的可能性,并有助于調(diào)試。
  • 并行化:不引發(fā)副作用的例程可以更容易地彼此并行運(yùn)行。

許多編程語(yǔ)言都在一定程度上支持函數(shù)式編程。在某些語(yǔ)言中,幾乎所有代碼都遵循函數(shù)式編程范式。Haskell 就是這樣的例子。而 Python 則同時(shí)支持函數(shù)式編程和其他編程模型。

雖然函數(shù)式編程的詳細(xì)描述確實(shí)較為復(fù)雜,但這里的目標(biāo)并不是提供嚴(yán)格的定義,而是展示如何在 Python 中進(jìn)行函數(shù)式編程。

Python 對(duì)函數(shù)式編程的支持如何?

為了支持函數(shù)式編程,如果一種編程語(yǔ)言中的函數(shù)能夠做到以下兩點(diǎn),將會(huì)非常有利:

  1. 接受另一個(gè)函數(shù)作為參數(shù)
  2. 返回另一個(gè)函數(shù)給調(diào)用者

Python 在這兩個(gè)方面都表現(xiàn)得很好。在 Python 中,一切皆為對(duì)象,所有對(duì)象在 Python 中的地位基本上是平等的,函數(shù)也不例外。

在 Python 中,函數(shù)是第一類公民。這意味著函數(shù)具有與字符串和數(shù)字等值相同的特性。任何可以對(duì)字符串或數(shù)字進(jìn)行的操作,也可以對(duì)函數(shù)進(jìn)行。

例如,您可以將一個(gè)函數(shù)賦值給一個(gè)變量,然后可以像使用該函數(shù)一樣使用該變量:

def func():
    print("I am function func()!")




func()


another_name = func
another_name()

圖片圖片

在第 7 行,通過(guò) another_name = func 這條語(yǔ)句創(chuàng)建了一個(gè)新的引用,指向函數(shù) func(),這個(gè)引用名為 another_name。隨后,您可以通過(guò) func 或 another_name 這兩個(gè)名稱來(lái)調(diào)用這個(gè)函數(shù),如第 5 行和第 8 行所示。

您可以使用 print() 將函數(shù)顯示在控制臺(tái)上,還可以將函數(shù)作為元素包含在復(fù)合數(shù)據(jù)對(duì)象(例如列表)中,甚至可以將其用作字典的鍵:

def func():
    print("I am function func()!")


print("cat", func, 42)


objects = ["cat", func, 42]
print(objects[1])


objects[1]()


d = {"cat": 1, func: 2, 42: 3}
d[func]

圖片圖片

在這個(gè)示例中,func() 出現(xiàn)在與值 "cat" 和 42 相同的上下文中,python解釋器都能正常處理它。

在當(dāng)前討論的上下文中,關(guān)鍵在于 Python 中的函數(shù)滿足了前面提到的對(duì)函數(shù)式編程有利的兩個(gè)標(biāo)準(zhǔn)。您可以將一個(gè)函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù):

def inner():
    print("I am function inner()!")


def outer(function):
    function()


outer(inner)

圖片圖片

以上示例的過(guò)程如下:

  • 在第 7 行中,inner() 被作為參數(shù)傳遞給 outer()。
  • 在 outer() 內(nèi)部,Python 將 inner() 綁定到函數(shù)參數(shù) function。
  • 然后 outer() 可以直接使用 function 來(lái)調(diào)用 inner()。

這被稱為函數(shù)組合。需要注意的是,您傳遞的是函數(shù)對(duì)象本身作為參數(shù)。如果您使用括號(hào)來(lái)調(diào)用函數(shù)對(duì)象,那么您傳遞的將不是函數(shù)對(duì)象,而是它的返回值。

當(dāng)您將一個(gè)函數(shù)傳遞給另一個(gè)函數(shù)時(shí),被傳遞的函數(shù)有時(shí)被稱為回調(diào)函數(shù)(callback),因?yàn)閷?duì)內(nèi)部函數(shù)的調(diào)用可以修改外部函數(shù)的行為。

一個(gè)很好的例子是 Python 中的 sorted() 函數(shù)。通常,如果您將一個(gè)字符串列表傳遞給 sorted(),它會(huì)按照字典順序進(jìn)行排序:

圖片圖片

然而,sorted() 接受一個(gè)可選的 key 參數(shù),該參數(shù)指定一個(gè)回調(diào)函數(shù)作為排序的依據(jù)。因此,例如,您可以按照字符串的長(zhǎng)度進(jìn)行排序:

animals = ["ferret", "vole", "dog", "gecko"]
sorted(animals, key=len)

圖片圖片

sorted() 還可以接受一個(gè)可選的參數(shù),用于指定是否以反向順序排序。但是,您也可以通過(guò)定義自己的回調(diào)函數(shù)來(lái)實(shí)現(xiàn)相同的效果,例如編寫(xiě)一個(gè)函數(shù)來(lái)反轉(zhuǎn) len() 的排序順序:

animals = ["ferret", "vole", "dog", "gecko"]
sorted(animals, key=len, reverse=True)


def reverse_len(s):
    return -len(s)


sorted(animals, key=reverse_len)

圖片圖片

正如您可以將一個(gè)函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù)一樣,函數(shù)也可以指定另一個(gè)函數(shù)作為其返回值:

def outer():
    def inner():
        print("I am function inner()!")
    # Function outer() returns function inner()
    return inner


function = outer()
print( function )


function()


outer()()

圖片圖片

在這個(gè)示例中發(fā)生的過(guò)程如下:

  • 第 2 到 3 行:outer() 定義了一個(gè)局部函數(shù) inner()。
  • 第 5 行:outer() 將 inner() 作為返回值返回。
  • 第 87行:您將 outer() 的返回值賦給變量 function。
  • 之后,您可以通過(guò) function 間接調(diào)用 inner(),如第 10 行所示。也可以通過(guò) outer() 的返回值直接調(diào)用 inner(),如第 12 行所示,無(wú)需中間賦值。

如您所見(jiàn),Python 擁有支持函數(shù)式編程的所有必要組件。但在深入函數(shù)式代碼之前,還有一個(gè)概念很有幫助,那就是lambda 表達(dá)式。

使用 lambda 定義匿名函數(shù)

函數(shù)式編程的核心是調(diào)用和傳遞函數(shù),因此通常涉及大量的函數(shù)定義。您可以像往常一樣使用 def 關(guān)鍵字定義函數(shù)。

有時(shí),能夠在不需要給函數(shù)命名的情況下定義一個(gè)匿名函數(shù)會(huì)很方便。在 Python 中,您可以使用 lambda 表達(dá)式來(lái)實(shí)現(xiàn)這一點(diǎn)。

lambda 表達(dá)式的語(yǔ)法如下:

lambda <parameter_list>: <expression>

以下表格總結(jié)了 lambda 表達(dá)式的各個(gè)部分:

組件

說(shuō)明

lambda

引入 lambda 表達(dá)式的關(guān)鍵字

<parameter_list>

可選的用逗號(hào)分隔的參數(shù)名稱列表

:

標(biāo)點(diǎn)符號(hào),用于分隔 <parameter_list> 和 <expression>

<expression>

通常涉及 <parameter_list> 中名稱的表達(dá)式,表示 lambda 函數(shù)的返回值

lambda 表達(dá)式的值是一個(gè)可調(diào)用的函數(shù),類似于使用 def 關(guān)鍵字定義的函數(shù)。它接受由 <parameter_list> 指定的參數(shù),并返回由 <expression> 指定的值。

以下是一個(gè)簡(jiǎn)單的示例:

圖片圖片

第 1 行的語(yǔ)句只是 lambda 表達(dá)式本身。

內(nèi)置的 Python 函數(shù) callable() 如果傳遞給它的參數(shù)看起來(lái)是可調(diào)用的,則返回 True,否則返回 False。第 3 行顯示了 lambda 表達(dá)式返回的值實(shí)際上是可調(diào)用的,就像一個(gè)函數(shù)應(yīng)該的那樣。

在這個(gè)例子中,參數(shù)列表包含一個(gè)參數(shù) s。隨后的表達(dá)式 s[::-1] 是切片語(yǔ)法,用于以相反的順序返回 s 中的字符。因此,這個(gè) lambda 表達(dá)式定義了一個(gè)臨時(shí)的無(wú)名函數(shù),它接受一個(gè)字符串參數(shù)并返回字符順序顛倒的字符串。

由 lambda 表達(dá)式創(chuàng)建的對(duì)象是第一類公民,就像標(biāo)準(zhǔn)函數(shù)或 Python 中的任何其他對(duì)象一樣。您可以將其賦值給一個(gè)變量,然后使用該名稱調(diào)用函數(shù):

reverse = lambda s: s[::-1]
reverse("I am a string")

圖片圖片

然而,在調(diào)用 lambda 表達(dá)式定義的函數(shù)之前,您不一定需要將其賦值給一個(gè)變量。您也可以直接調(diào)用由 lambda 表達(dá)式定義的函數(shù):

(lambda s: s[::-1])("I am a string")

圖片圖片

您將 lambda 表達(dá)式括在括號(hào)中以明確其結(jié)束位置,然后添加了一組括號(hào),并將 "I am a string" 作為參數(shù)傳遞給您的匿名函數(shù)。Python 將字符串參數(shù)分配給參數(shù) s,然后您的 lambda 函數(shù)反轉(zhuǎn)了字符串并返回結(jié)果。

這是另一個(gè)示例,基于相同的概念,但因?yàn)樵?nbsp;lambda 表達(dá)式中使用了多個(gè)參數(shù),所以更加復(fù)雜:

a= (lambda x1, x2, x3: (x1 + x2 + x3) / 3)(9, 6, 6)
print(a)
(lambda x1, x2, x3: (x1 + x2 + x3) / 3)(1.4, 1.1, 0.5)

圖片圖片

在這個(gè)例子中,參數(shù)是 x1、x2 和 x3,表達(dá)式是 x1 + x2 + x3 / 3。這是一個(gè)匿名 lambda 函數(shù),用于計(jì)算三個(gè)數(shù)字的平均值。

使用 lambda 表達(dá)式的真正優(yōu)勢(shì)在于它們適用于短小而直接的邏輯。您可以用一個(gè)簡(jiǎn)潔直接的 lambda 表達(dá)式來(lái)代替定義 reverse_len:

圖片圖片

lambda 表達(dá)式通常會(huì)有一個(gè)參數(shù)列表,但這不是必須的。您可以定義一個(gè)沒(méi)有參數(shù)的 lambda 函數(shù)。在這種情況下,返回值不依賴于任何輸入?yún)?shù):

圖片圖片

lambda 只能用于定義比較簡(jiǎn)單的函數(shù)。lambda 表達(dá)式的返回值只能是一個(gè)單一的表達(dá)式。lambda 表達(dá)式不能包含諸如賦值或 return 的語(yǔ)句,也不能包含控制結(jié)構(gòu),如 for、while、if、else 或 def。

lambda 函數(shù)在編寫(xiě)函數(shù)式代碼時(shí)特別方便。Python 提供了兩個(gè)內(nèi)置函數(shù) map() 和 filter(),它們符合函數(shù)式編程范式。第三個(gè)函數(shù) reduce() 不再是核心語(yǔ)言的一部分,但仍然可以在名為 functools 的模塊中使用。這三個(gè)函數(shù)中的每一個(gè)都將另一個(gè)函數(shù)作為其參數(shù)之一。

使用 map() 對(duì)可迭代對(duì)象應(yīng)用函數(shù)

第一個(gè)要介紹的函數(shù)是 map(),這是 Python 的一個(gè)內(nèi)置函數(shù)。使用 map(),您可以依次將一個(gè)函數(shù)應(yīng)用于可迭代對(duì)象中的每個(gè)元素。map() 函數(shù)將返回一個(gè)迭代器,該迭代器生成結(jié)果。這可以使代碼變得非常簡(jiǎn)潔,因?yàn)?nbsp;map() 語(yǔ)句通??梢蕴娲@式的循環(huán)。

您可以使用一個(gè)可迭代對(duì)象或多個(gè)可迭代對(duì)象來(lái)調(diào)用 map()。接下來(lái),您將查看在單個(gè)可迭代對(duì)象上調(diào)用 map() 的語(yǔ)法。

map(<f>, <iterable>) 返回一個(gè)迭代器,該迭代器生成將函數(shù) <f> 應(yīng)用到 <iterable> 中每個(gè)元素的結(jié)果。

下面是一個(gè)示例。假設(shè)您已經(jīng)定義了 reverse() 函數(shù),該函數(shù)接受一個(gè)字符串參數(shù),并使用舊友 [::-1] 字符串切片機(jī)制返回其反轉(zhuǎn)結(jié)果;如果您有一個(gè)字符串列表,可以使用 map() 將 reverse() 應(yīng)用到列表中的每個(gè)元素:

def reverse(s):
    return s[::-1]


print( reverse("I am a string") )


animals = ["cat", "dog", "hedgehog", "gecko"]
print( map(reverse, animals) )
list( map(reverse, animals) )

圖片圖片

map() 不會(huì)返回一個(gè)列表。它返回的是一個(gè) map 對(duì)象,這是一個(gè)迭代器。

使用多個(gè)可迭代對(duì)象調(diào)用 map()

另一種使用 map() 的方式是,當(dāng)您在函數(shù)參數(shù)后傳遞多個(gè)可迭代對(duì)象時(shí):

map(<f>, <iterable?>, <iterable?>, ..., <iterable?>)

在這個(gè)例子中,map(<f>, <iterable1>, <iterable2>, ..., <iterablen>) 會(huì)將 <f> 應(yīng)用到每個(gè) <iterablei> 中的元素,并且以并行的方式返回一個(gè)迭代器,生成結(jié)果。

傳遞給 map() 的 <iterablei> 參數(shù)的數(shù)量必須與 <f> 預(yù)期的參數(shù)數(shù)量匹配。<f> 作用于每個(gè) <iterablei> 的第一個(gè)項(xiàng)目,生成的結(jié)果成為返回迭代器的第一個(gè)生成項(xiàng)。然后,<f> 作用于每個(gè) <iterablei> 的第二個(gè)項(xiàng)目,生成的結(jié)果成為第二個(gè)生成項(xiàng),以此類推。

一個(gè)詳細(xì)的示例可以幫助您更清楚地理解:

def add_three(a, b, c):
    return a + b + c


list(map(add_three, [1, 2, 3], [10, 20, 30], [100, 200, 300]))

圖片圖片

第一項(xiàng)是計(jì)算 add_three(1, 10, 100),第二項(xiàng)是計(jì)算 add_three(2, 20, 200) 的結(jié)果,第三項(xiàng)是計(jì)算 add_three(3, 30, 300) 的結(jié)果。這可以通過(guò)以下示意圖來(lái)表示:

圖片圖片

使用 filter() 從可迭代對(duì)象中選擇元素

filter() 允許您根據(jù)給定函數(shù)的評(píng)估來(lái)選擇或過(guò)濾可迭代對(duì)象中的項(xiàng)。其函數(shù)如下:

filter(<f>, <iterable>)

filter(<f>, <iterable>) 將函數(shù) <f> 應(yīng)用到 <iterable> 中的每個(gè)元素,并返回一個(gè)迭代器,該迭代器生成所有 <f> 結(jié)果為真值的項(xiàng)。相反,它會(huì)過(guò)濾掉所有 <f> 結(jié)果為假值的項(xiàng)。

在以下示例中,如果 x > 100,greater_than_100(x) 就會(huì)返回真值:

def greater_than_100(x):
    return x > 100


list(filter(greater_than_100, [1, 111, 2, 222, 3, 333]))

圖片圖片

在這種情況下,greater_than_100() 對(duì)項(xiàng) 111、222 和 333 產(chǎn)生真值,因此這些項(xiàng)會(huì)保留,而 filter() 會(huì)丟棄 1、2 和 3。與之前的示例一樣,greater_than_100() 是一個(gè)簡(jiǎn)短的函數(shù),您可以用 lambda 表達(dá)式替代它:

圖片圖片

使用 reduce() 將可迭代對(duì)象歸約為單一值

reduce() 將一個(gè)函數(shù)應(yīng)用于可迭代對(duì)象中的項(xiàng),每次兩個(gè)項(xiàng)一同處理,逐步合并它們以生成一個(gè)最終結(jié)果。

最直接的reduce()調(diào)用需要一個(gè)函數(shù)和一個(gè)可迭代對(duì)象:

reduce(<f>,<iterable>)

在調(diào)用 時(shí)reduce(<f>, <iterable>),函數(shù)<f>必須是采用兩個(gè)參數(shù)的函數(shù)。然后將使用reduce()逐步組合 中的元素。首先,對(duì) 的前兩個(gè)元素調(diào)用。然后將該結(jié)果與第三個(gè)元素組合,然后將該結(jié)果與第四個(gè)元素組合,依此類推,直到列表用盡。然后,返回最終結(jié)果。

def f(x, y):
    return x + y


from functools import reduce
reduce(f, [1, 2, 3, 4, 5])

圖片圖片

此調(diào)用將產(chǎn)生列表的reduce()結(jié)果,如下所示:

圖片圖片

這是對(duì)列表中的數(shù)字求和的一種相當(dāng)迂回的方法。

函數(shù)式編程是一種編程范式,其中主要的計(jì)算方法是純函數(shù)的求值。盡管 Python 主要不是函數(shù)式語(yǔ)言,但您仍然可以按照函數(shù)式編程原則編寫(xiě) Python。最好熟悉lambda、map()、filter()和reduce()。它們可以幫助您編寫(xiě)簡(jiǎn)潔、高級(jí)、可并行的代碼。您可能還會(huì)在其他人編寫(xiě)的代碼中看到這些函數(shù)的使用,因此了解它們的工作原理是很好的。

責(zé)任編輯:武曉燕 來(lái)源: 新語(yǔ)數(shù)據(jù)故事匯
相關(guān)推薦

2024-07-11 12:14:20

Pythonmapfilter

2019-08-06 09:00:00

JavaScript函數(shù)式編程前端

2024-10-06 14:01:47

Python裝飾器對(duì)象編程

2024-01-10 08:47:48

Python函數(shù)Map()

2025-04-11 08:00:00

函數(shù)式編程Python

2024-05-21 09:45:40

機(jī)器學(xué)習(xí)人工智能XAI

2022-07-19 15:24:45

Python編程技術(shù)

2024-10-17 16:45:46

Python內(nèi)置函數(shù)

2024-10-08 10:44:32

2024-07-31 15:11:57

SymPypython數(shù)學(xué)運(yùn)算

2023-11-22 16:10:59

編程語(yǔ)言機(jī)器語(yǔ)言

2025-01-06 07:54:13

SPC控制圖工具

2024-06-04 00:20:00

Python函數(shù)

2024-03-08 09:45:21

Lambda表達(dá)式Stream

2025-02-05 12:06:15

正態(tài)分?jǐn)?shù)變換NST

2023-12-26 01:14:20

函數(shù)式編程死鎖

2024-03-12 17:54:55

容器類型Init

2023-05-31 13:32:08

Javalambda函數(shù)

2010-10-25 15:04:39

Oracle文本函數(shù)

2010-10-09 14:00:10

mysql CONCA
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)