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

Python 函數(shù)式編程,看這一篇就夠了!

開(kāi)發(fā) 后端
在 Python 中,函數(shù)是「頭等公民」(first-class)。也就是說(shuō),函數(shù)與其他數(shù)據(jù)類型(如 int)處于平等地位。

本文對(duì) Python 中的函數(shù)式編程技術(shù)進(jìn)行了簡(jiǎn)單的入門(mén)介紹。

頭等函數(shù)

在 Python 中,函數(shù)是「頭等公民」(first-class)。也就是說(shuō),函數(shù)與其他數(shù)據(jù)類型(如 int)處于平等地位。

因而,我們可以將函數(shù)賦值給變量,也可以將其作為參數(shù)傳入其他函數(shù),將它們存儲(chǔ)在其他數(shù)據(jù)結(jié)構(gòu)(如 dicts)中,并將它們作為其他函數(shù)的返回值。

把函數(shù)作為對(duì)象

由于其他數(shù)據(jù)類型(如 string、list 和 int)都是對(duì)象,那么函數(shù)也是 Python 中的對(duì)象。我們來(lái)看示例函數(shù) foo,它將自己的名稱打印出來(lái):

def foo():
print("foo")

由于函數(shù)是對(duì)象,因此我們可以將函數(shù) foo 賦值給任意變量,然后調(diào)用該變量。例如,我們可以將函數(shù)賦值給變量 bar:

bar = foo
bar()
#will print "foo" to the console

語(yǔ)句 bar = foo 將函數(shù) foo 引用的對(duì)象賦值給變量 bar。

把對(duì)象作為函數(shù)

當(dāng)對(duì)象可調(diào)用時(shí)(callable),它們與函數(shù)一樣,如 object()。這是通過(guò) __call__ 方法實(shí)現(xiàn)的。

示例如下:

class Greeter:
def __init__(self, greeting):
self.greeting = greeting
def __call__(self, name):
return self.greeting + " " + name

每一次配置 Greeter 類的對(duì)象時(shí),我們都會(huì)創(chuàng)建一個(gè)新的對(duì)象,即打招呼時(shí)可以喊的新名字。如下所示:

morning = Greeter("good morning") #creates the callable object
morning("john") # calling the object
#prints "good morning john" to the console

我們可以調(diào)用 morning 對(duì)象的原因在于,我們已經(jīng)在類定義中使用了 __call__ 方法。為了檢查對(duì)象是否可調(diào)用,我們使用內(nèi)置函數(shù) callable:

callable(morning) #true
callable(145) #false. int is not callable.

數(shù)據(jù)結(jié)構(gòu)內(nèi)的函數(shù)

函數(shù)和其他對(duì)象一樣,可以存儲(chǔ)在數(shù)據(jù)結(jié)構(gòu)內(nèi)部。例如,我們可以創(chuàng)建 int to func 的字典。當(dāng) int 是待執(zhí)行步驟的簡(jiǎn)寫(xiě)時(shí),這就會(huì)派上用場(chǎng)。

# store in dictionary
mapping = {
0 : foo,
1 : bar
}
x = input() #get integer value from user
mapping[x]() #call the func returned by dictionary access

類似地,函數(shù)也可以存儲(chǔ)在多種其他數(shù)據(jù)結(jié)構(gòu)中。

把函數(shù)作為參數(shù)和返回值

函數(shù)還可以作為其他函數(shù)的參數(shù)和返回值。接受函數(shù)作為輸入或返回函數(shù)的函數(shù)叫做高階函數(shù),它是函數(shù)式編程的重要組成部分。

高階函數(shù)具備強(qiáng)大的能力。就像《Eloquent JavaScript》中解釋的那樣:

  • 「高階函數(shù)允許我們對(duì)動(dòng)作執(zhí)行抽象,而不只是抽象數(shù)值?!?/li>

我們來(lái)看一個(gè)例子。假設(shè)我們想對(duì)一個(gè)項(xiàng)目列表(list of items)執(zhí)行迭代,并將其順序打印出來(lái)。我們可以輕松構(gòu)建一個(gè) iterate 函數(shù):

def iterate(list_of_items):
for item in list_of_items:
print(item)

看起來(lái)很酷吧,但這只不過(guò)是一級(jí)抽象而已。如果我們想在對(duì)列表執(zhí)行迭代時(shí)進(jìn)行打印以外的其他操作要怎么做呢?

這就是高階函數(shù)存在的意義。我們可以創(chuàng)建函數(shù) iterate_custom,待執(zhí)行迭代的列表和要對(duì)每個(gè)項(xiàng)應(yīng)用的函數(shù)都是 iterate_custom 函數(shù)的輸入:

def iterate_custom(list_of_items, custom_func):
for item in list_of_items:
custom_func(item)

這看起來(lái)微不足道,但其實(shí)非常強(qiáng)大。

我們已經(jīng)把抽象的級(jí)別提高了一層,使代碼具備更強(qiáng)的可重用性?,F(xiàn)在,我們不僅可以在打印列表時(shí)調(diào)用該函數(shù),還可以對(duì)涉及序列迭代的列表執(zhí)行任意操作。

函數(shù)還能被返回,從而使事情變得更加簡(jiǎn)單。就像我們?cè)?dict 中存儲(chǔ)函數(shù)一樣,我們還可以將函數(shù)作為控制語(yǔ)句,來(lái)決定適合的函數(shù)。例如:

def add(x, y):
return x + y
def sub(x, y):
return x - y
def mult(x, y):
return x * y
def calculator(opcode):
if opcode == 1:
return add
elif opcode == 2:
return sub
else:
return mult
my_calc = calculator(2) #my calc is a subtractor
my_calc(5, 4) #returns 5 - 4 = 1
my_calc = calculator(9) #my calc is now a multiplier
my_calc(5, 4) #returns 5 x 4 = 20.

嵌套函數(shù)

函數(shù)還可以在其他函數(shù)內(nèi)部,這就是「內(nèi)部函數(shù)」。內(nèi)部函數(shù)在創(chuàng)建輔助函數(shù)時(shí)非常有用,輔助函數(shù)即作為子模塊來(lái)支持主函數(shù)的小型可重用函數(shù)。

在問(wèn)題需要特定函數(shù)定義(參數(shù)類型或順序)時(shí),我們可以使用輔助函數(shù)。這種不遵循傳統(tǒng)做法的操作使得解決問(wèn)題變得更加簡(jiǎn)單,示例參見(jiàn):http://www-inst.eecs.berkeley.edu/~cs61a/sp12/lectures/lect4-2x3.pdf。

假設(shè)你想定義一個(gè)斐波那契函數(shù) fib(n),該函數(shù)只有一個(gè)參數(shù) n,我們必須返回第 n 個(gè)斐波那契數(shù)。

定義此類函數(shù)的一種可行方式是:使用輔助函數(shù)來(lái)追蹤斐波那契數(shù)列的前兩個(gè)項(xiàng)(因?yàn)殪巢瞧鯏?shù)是前兩個(gè)數(shù)之和)。

def fib(n):
def fib_helper(fk1, fk, k):
if n == k:
return fk
else:
return fib_helper(fk, fk1+fk, k+1)
if n <= 1:
return n
else:
return fib_helper(0, 1, 1)

將該計(jì)算從函數(shù)主體移到函數(shù)參數(shù),這具備非常強(qiáng)大的力量。因?yàn)樗鼫p少了遞歸方法中可能出現(xiàn)的冗余計(jì)算。

單表達(dá)式函數(shù)(Lambda 表達(dá)式)

如果我們想在未給函數(shù)命名之前寫(xiě)一個(gè)函數(shù)要怎么做?如果我們想寫(xiě)一個(gè)簡(jiǎn)短的單行函數(shù)(如上述示例中的函數(shù) foo 或 mult)要怎么做?

我們可以在 Python 中使用 lambda 關(guān)鍵字來(lái)定義此類函數(shù)。示例如下:

mult = lambda x, y: x * y
mult(1, 2) #returns 2

該 mult 函數(shù)的行為與使用傳統(tǒng) def 關(guān)鍵字定義函數(shù)的行為相同。

注意:lambda 函數(shù)必須為單行,且不能包含程序員寫(xiě)的返回語(yǔ)句。

事實(shí)上,它們通常具備隱式的返回語(yǔ)句(在上面的示例中,函數(shù)想表達(dá) return x * y,不過(guò)我們省略了 lambda 函數(shù)中的顯式返回語(yǔ)句)。

lambda 函數(shù)更加強(qiáng)大和精準(zhǔn),因?yàn)槲覀冞€可以構(gòu)建匿名函數(shù)(即沒(méi)有名稱的函數(shù)):

(lambda x, y: x * y)(9, 10) #returns 90

當(dāng)我們只需要一次性使用某函數(shù)時(shí),這種方法非常方便。例如,當(dāng)我們想填充字典時(shí):

import collections
pre_fill = collections.defaultdict(lambda: (0, 0))
#all dictionary keys and values are set to 0

接下來(lái)我們來(lái)看 Map、Filter 和 Reduce,以更多地了解 lambda。

Map、Filter 和 Reduce

Map

map 函數(shù)基于指定過(guò)程(函數(shù))將輸入集轉(zhuǎn)換為另一個(gè)集合。這類似于上文提到的 iterate_custom 函數(shù)。例如:

def multiply_by_four(x):
return x * 4
scores = [3, 6, 8, 3, 5, 7]
modified_scores = list(map(multiply_by_four, scores))
#modified scores is now [12, 24, 32, 12, 20, 28]

在 Python 3 中,map 函數(shù)返回的 map 對(duì)象可被類型轉(zhuǎn)換為 list,以方便使用?,F(xiàn)在,我們無(wú)需顯式地定義 multiply_by_four 函數(shù),而是定義 lambda 表達(dá)式:

modified_scores = list(map(lambda x: 4 * x, scores))

當(dāng)我們想對(duì)集合內(nèi)的所有值執(zhí)行某項(xiàng)操作時(shí),map 函數(shù)很有用。

Filter

就像名稱所顯示的那樣,filter 函數(shù)可以幫助篩除不想要的項(xiàng)。例如,我們想要去除 scores 中的奇數(shù),那么我們可以使用 filter:

even_scores = list(filter(lambda x: True if (x % 2 == 0) else False, scores))
#even_scores = [6, 8]

由于提供給 filter 的函數(shù)是逐個(gè)決定是否接受每一個(gè)項(xiàng)的,因此該函數(shù)必須返回 bool 值,且該函數(shù)必須是一元函數(shù)(即只使用一個(gè)輸入?yún)?shù))。

Reduce

reduce 函數(shù)用于「總結(jié)」或「概述」數(shù)據(jù)集。例如,如果我們想要計(jì)算所有分?jǐn)?shù)的總和,就可以使用 reduce:

sum_scores = reduce((lambda x, y: x + y), scores)
#sum_scores = 32

這要比寫(xiě)循環(huán)語(yǔ)句簡(jiǎn)單多了。注意:提供給 reduce 的函數(shù)需要兩個(gè)參數(shù):一個(gè)表示正在接受檢查的項(xiàng),另一個(gè)表示所用運(yùn)算的累積結(jié)果。

本文是關(guān)于函數(shù)式編程的一篇入門(mén)文章,雖然盡量完備地介紹了相關(guān)的知識(shí),但并不是那么深入。如想了解更多,大家可以閱讀以下資源:

  • Best Practices for Using Functional Programming in Python:https://kite.com/blog/python/functional-programming/
  • Functional Programming Tutorials and Notes:https://www.hackerearth.com/zh/practice/python/functional-programming/functional-programming-1/tutorial/
責(zé)任編輯:龐桂玉 來(lái)源: 小詹學(xué)Python
相關(guān)推薦

2018-05-22 08:24:50

PythonPyMongoMongoDB

2023-02-10 09:04:27

2020-02-18 16:20:03

Redis ANSI C語(yǔ)言日志型

2022-06-20 09:01:23

Git插件項(xiàng)目

2022-08-01 11:33:09

用戶分析標(biāo)簽策略

2021-04-08 07:37:39

隊(duì)列數(shù)據(jù)結(jié)構(gòu)算法

2023-09-11 08:13:03

分布式跟蹤工具

2017-03-13 09:50:46

Python裝飾器

2023-10-17 08:15:28

API前后端分離

2024-09-23 08:00:00

消息隊(duì)列MQ分布式系統(tǒng)

2020-07-03 08:21:57

Java集合框架

2019-05-14 09:31:16

架構(gòu)整潔軟件編程范式

2017-03-11 22:19:09

深度學(xué)習(xí)

2022-04-07 10:39:21

反射Java安全

2023-11-18 09:30:42

模型AI

2019-04-01 10:43:59

Linux問(wèn)題故障

2022-05-19 08:28:19

索引數(shù)據(jù)庫(kù)

2020-10-21 14:12:02

Single Sign

2023-11-06 07:21:13

內(nèi)存結(jié)構(gòu)Jvm

2020-10-18 07:32:06

SD-WAN網(wǎng)絡(luò)傳統(tǒng)廣域網(wǎng)
點(diǎn)贊
收藏

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