Python 函数式编程指北,不只是面向对象哦
了解在Python中如何使用 lambda, map, filter 和 reduce 函數(shù)來(lái)轉(zhuǎn)換數(shù)據(jù)結(jié)構(gòu)
Photo by Markus Spiske on Unsplash
面向?qū)ο蟮木幊掏ㄟ^(guò)封裝移動(dòng)部件來(lái)讓代碼變得易于理解,而函數(shù)式編程則通過(guò)盡量減少移動(dòng)部件來(lái)使代碼變得易于理解。— Michael Feathers
世界上有很多種語(yǔ)言,它們可以歸類的類別也是如此。編程示例是一種基于編碼風(fēng)格和語(yǔ)言方式去嘗試把不同語(yǔ)言分類的途徑。編程示例本質(zhì)上就是一種風(fēng)格和編程方式。
大多數(shù)的時(shí)候,我們認(rèn)為 Python 是面向?qū)ο?/strong>語(yǔ)言, 我們以 類(classes),對(duì)象(objects),和方法(methods)對(duì)數(shù)據(jù)進(jìn)行模擬。但是,OOP 也有幾種替代方案,函數(shù)式編程就是其中之一。
以下是業(yè)界流行的一些傳統(tǒng)編程示例:
常規(guī)編程示例:來(lái)源 Wikipedia
1、函數(shù)式編程(FP)
函數(shù)式方程示例
根據(jù)維基百科, 函數(shù)式方程 是一種函數(shù)式示例, 是構(gòu)建計(jì)算機(jī)程序結(jié)構(gòu)和基本要素的一種風(fēng)格。它將計(jì)算視為數(shù)學(xué)函數(shù)的評(píng)估和避免改變數(shù)據(jù)和其狀態(tài)。
上面的定義有可能一開(kāi)始聽(tīng)起來(lái)很讓人迷惑,但它基本上試圖提出以下觀點(diǎn):
- FP 依賴于方程,一切都是使用函數(shù)來(lái)完成的。并且,FP 專注于定義去做什么,而不是執(zhí)行某些操作。這種函數(shù)示例被認(rèn)為是一級(jí)函數(shù)式。這意味著函數(shù)被視為任何其它對(duì)象,我們可以把他們分配給變量或者將他們嵌入其它函數(shù)式。
- 函數(shù)式使用的數(shù)據(jù)必須是不可變的。這意味著如果我們需要修改列表中的數(shù)據(jù),我們需要新建一個(gè)包含更新值的新列表,而不是操縱現(xiàn)有的列表。
- 寫入FP的程序應(yīng)該是無(wú)狀態(tài)的。無(wú)狀態(tài)的方程式不能表達(dá)其過(guò)去狀態(tài)。函數(shù)式編程每一次執(zhí)行任務(wù),就像他們第一次執(zhí)行一樣。簡(jiǎn)而言之,這些函數(shù)僅依賴于作為參數(shù)傳遞給他們的數(shù)據(jù),而不依賴于外部數(shù)據(jù)。
- 惰性是 FP 另外一個(gè)特性,我們不需要計(jì)算我們不需要的東西,工作只在需要時(shí)完成。
如果現(xiàn)在有所了解,下面是 OOP 和 FP 很好的對(duì)比圖表,這將概念變得更明顯。
圖片來(lái)源: www.educba.com
Python提供了 lambda,filter,map 和 reduce 等功能,可以輕松演示函數(shù)式編程的概念。可以從關(guān)聯(lián)的 Github 存儲(chǔ)庫(kù) 訪問(wèn)本文中使用的所有代碼.
https://github.com/parulnith/Elements-of-Functional-Programming-in-Python
2、Lambda 表達(dá)式
Lambda 表達(dá)式 - 也稱為“匿名函數(shù)” - 允許我們?cè)谝恍兄袆?chuàng)建和使用函數(shù)。當(dāng)我們需要一個(gè)只能使用一次的短函數(shù)時(shí)它們很有用。它們主要與 map,filter 和 sort 方法結(jié)合使用,我們將在本文后面講到。
讓我們用 Python 編寫一個(gè)函數(shù)來(lái)計(jì)算 5x + 2. 標(biāo)準(zhǔn)的做法是定義一個(gè)函數(shù)。
現(xiàn)在讓我們使用 Lambda 函數(shù)計(jì)算相同的表達(dá)式。要?jiǎng)?chuàng)建 lambda 表達(dá)式,我們輸入關(guān)鍵字 lambda,后面輸入函數(shù)。接下來(lái),我們輸入一個(gè)冒號(hào),后面是返回值的表達(dá)式。
這個(gè) lambda 函數(shù)將獲取輸入 x 并返回 5x + 2,就像之前的函數(shù)一樣 f 。但是,有一個(gè)問(wèn)題。Lambda 不是函數(shù)的名稱。它是一個(gè) Python 關(guān)鍵字,表示接下來(lái)是一個(gè)匿名函數(shù)。那么我們?nèi)绾问褂盟?#xff1f;一種方法是給它起一個(gè)名字。
讓我們稱之為 lambda 表達(dá)式 g。現(xiàn)在,我們可以像任何其他功能一樣使用它。
具有多個(gè)輸入值的Lambda表達(dá)式
下面的示例顯示了lambda函數(shù)如何在有或沒(méi)有輸入值的情況下使用。
沒(méi)有輸入值的Lambda表達(dá)式
現(xiàn)在,讓我們看看 Lambda 函數(shù)的常見(jiàn)用法,我們不為它指定名稱。假設(shè)我們列出了前七位美國(guó)總統(tǒng)的名單,我們想用他們的姓氏對(duì)這份名單進(jìn)行排序。我們將創(chuàng)建一個(gè)提取姓氏的 Lambda 函數(shù),并將其用作排序值。
map,filter 和 reduce 函數(shù)簡(jiǎn)化了使用列表的工作。與 lambda 表達(dá)式一起使用時(shí),它們通過(guò)在一行代碼中完成大量工作,有助于使我們的生活更輕松。
3、Map 函數(shù)
Map 函數(shù)對(duì)每一個(gè)數(shù)值進(jìn)行迭代并產(chǎn)生的結(jié)果。與列表一起使用時(shí),Map通過(guò)將函數(shù)應(yīng)用于在input_list中的所有值,將給定列表轉(zhuǎn)換為新列表。
句法
map(function_to_apply, iterables)用法
假設(shè)我們有一個(gè)函數(shù)來(lái)計(jì)算一個(gè)立方體的體積,給定它的邊長(zhǎng) a
def volume(a): """volumne of a cube with edge 'a'""" return a**3如果我們需要計(jì)算具有不同邊長(zhǎng)的不同立方體的體積,該怎么辦?
# Edge length in cmedges = [1,2,3,4,5]有兩種方法可以做到這一點(diǎn), 一種是使用直接方法,另一種是使用 map 函數(shù)。
現(xiàn)在讓我們看看如何使用 map 函數(shù)使用一行代碼來(lái)完成此任務(wù)。
Map 函數(shù)有兩個(gè)參數(shù)。第一個(gè)是函數(shù),第二個(gè)是我們的 list ,tuple 或任何其他可迭代對(duì)象。這里,map 函數(shù)將 volume 函數(shù)應(yīng)用于列表中的每個(gè)元素。
這里要注意的一件重要事情是 map 函數(shù)的輸出不是列表而是 map 對(duì)象,它是結(jié)果的迭代器。但是,我們可以通過(guò)將映射傳遞構(gòu)造列表將其轉(zhuǎn)換為列表。
例子
現(xiàn)在讓我們看一個(gè)演示 lambda 函數(shù)與 map 函數(shù)一起使用的例子。我們有一個(gè)包含 5 個(gè)人姓名和高度的元組列表。每個(gè)高度都以厘米為單位,我們需要將其轉(zhuǎn)換為英尺。
我們將首先使用 lambda 表達(dá)式編寫轉(zhuǎn)換器函數(shù),該表達(dá)式將接受元組作為輸入,并且還將返回元組
4、Filter 函數(shù)
Filter 函數(shù)從可迭代元素中構(gòu)造一個(gè)迭代器,并且函數(shù)返回符合值。這意味著 filter 函數(shù)用于從 list,tuple 或其他數(shù)據(jù)集合中選擇某些數(shù)據(jù),因此叫這個(gè)名字。
句法
filter(function, iterable)用法
讓我們看一個(gè)例子,我們想要從給定的輸入列表中獲取大于 5 的所有數(shù)字的列表。
我們首先創(chuàng)建一個(gè)lambda函數(shù)來(lái)測(cè)試輸入,看它是否大于5。接下來(lái),我們傳入數(shù)據(jù)列表。Filter 函數(shù)僅返回函數(shù)為正確的數(shù)據(jù)。再一次,返回值不是列表,而是 filter 對(duì)象。必須將此對(duì)象傳遞給列表構(gòu)造函數(shù)才能獲得輸出。
例子
一個(gè)有趣的例子,當(dāng)數(shù)據(jù)由缺失值組成時(shí),filter 函數(shù)發(fā)生作用。這是一份包含亞洲一些國(guó)家的清單。注意很多字符串都是空的。我們將使用 filter 功能來(lái)刪除這些缺失值。我們將空集作為第一個(gè)參數(shù),第二個(gè)參數(shù)是剛剛提到的數(shù)據(jù)列表。
這會(huì)過(guò)濾掉布爾設(shè)置中被視為否的所有值。
5、Reduce 函數(shù)
Reduce 功能有點(diǎn)不尋常,從 Python 3 開(kāi)始,它不再是內(nèi)置函數(shù)。相反,它已被移動(dòng)到 functools 模塊。 reduce 函數(shù)通過(guò)將給定列表轉(zhuǎn)換為單個(gè)值,通過(guò)列表中值從左到右順序累加并返回一個(gè)值。
用法
reduce(func, seq)reduce 持續(xù)將函數(shù) func() 應(yīng)用于序列 seq 并返回單個(gè)值。
用法
讓我們通過(guò)一個(gè)計(jì)算整數(shù)列表連乘的簡(jiǎn)單例子來(lái)說(shuō)明 reduce 函數(shù)的工作原理。
下圖顯示了計(jì)算的中間步驟:
在 Python 中使用 Reduce 函數(shù)
然而,Python 的創(chuàng)建者 Guido van Rossum 不得不對(duì) Reduce 函數(shù)這樣說(shuō):
如果你確實(shí)需要,請(qǐng)使用 functools.reduce; 但是,99% 的時(shí)間表明 for 循環(huán)更具有可讀性。
上面的程序也可以使用顯式的 for 循環(huán)編寫:
例子
Reduce 函數(shù)可以用單行代碼找出整數(shù)列表中的最大值。確實(shí)在 Python 中存在一個(gè)內(nèi)置函數(shù) max(),它也通常可以用于此目的 max(list_name)。
6、列表推導(dǎo)式: 替代 map, filter 和 reduce
列表推導(dǎo)式(list comprehensions) 是一種在Python 中定義和創(chuàng)建列表的方法。在大多數(shù)情況下,列表理解使我們可以在一行代碼中創(chuàng)建列表,而無(wú)需擔(dān)心初始化列表或設(shè)置循環(huán)。
它也是 lambda 函數(shù)以及函數(shù) map(),filter()和reduce()的替代品。有些人發(fā)現(xiàn)它是一種更加體現(xiàn) python 的編寫函數(shù)的方式,并且發(fā)現(xiàn)它更容易理解。
句法
用法
讓我們嘗試用 列表推導(dǎo)式來(lái)演示上面部分使用的示例。
- 列表推導(dǎo)式 vs. Map 函數(shù)
我們將 map 函數(shù)與 lambda 函數(shù)結(jié)合使用,將高度列表從 cm 轉(zhuǎn)換為英尺。讓我們使用列表推導(dǎo)式來(lái)實(shí)現(xiàn)相同的結(jié)果。
- 列表推導(dǎo)式 vs. Filter 函數(shù)
我們使用過(guò)濾功能從亞洲國(guó)家/地區(qū)列表中刪除缺失值。讓我們使用列表推導(dǎo)式來(lái)獲得相同的結(jié)果。
- 列表推導(dǎo)式 vs. Reduce 函數(shù)
類似地,我們可以使用列表推導(dǎo)式來(lái)快速確定包含整數(shù)列表的最大值,而不是使用 lambda 和 reduce。
我們?cè)谏厦胬又惺褂昧讼鄳?yīng)函數(shù)式表達(dá),類似于列表推導(dǎo)式,但是使用圓括號(hào)而不是方括號(hào)。
7、結(jié)論
Map,Filter 和 Reduce 函數(shù)顯著簡(jiǎn)化了使用列表和其他可迭代數(shù)據(jù)集的過(guò)程。有些人對(duì)使用它們有所保留,特別是因?yàn)榱斜硗茖?dǎo)式似乎更友好,但它們的用處不容忽視。
總結(jié)
以上是生活随笔為你收集整理的Python 函数式编程指北,不只是面向对象哦的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Python 命令行之旅:深入 clic
- 下一篇: websocket python爬虫_p