0x00. 概述
在熟悉了Python基礎(chǔ)知識(shí)后螟蝙,我們已經(jīng)可以做一些腳本開(kāi)發(fā),或者簡(jiǎn)單的程序副瀑。然而弓熏,當(dāng)我們開(kāi)發(fā)較為復(fù)雜的程序時(shí),僅使用基礎(chǔ)知識(shí)內(nèi)容就會(huì)顯得比較吃力糠睡。這時(shí)挽鞠,了解Python中的一些高級(jí)特性會(huì)使我們的開(kāi)發(fā)過(guò)程變得簡(jiǎn)單和快樂(lè)。
閱讀本篇文章,筆者默認(rèn)您已經(jīng)掌握Python基礎(chǔ)知識(shí)信认。如果您對(duì)Python還不了解材义,請(qǐng)參考Python筆記(一):基礎(chǔ)知識(shí)
PS:本打算把幾個(gè)高級(jí)特性都寫(xiě)到一篇文章里,但是后來(lái)想了想如果真這樣的話(huà)文章就太長(zhǎng)了嫁赏,索性分開(kāi)來(lái)講其掂,獨(dú)自成文,也可以講的更細(xì)一點(diǎn)潦蝇。
0x01. 介紹
在數(shù)學(xué)和計(jì)算機(jī)科學(xué)中款熬,高階函數(shù)是至少滿(mǎn)足下列一個(gè)條件的函數(shù):
接受一個(gè)或多個(gè)函數(shù)作為輸入
輸出一個(gè)函數(shù)
——摘自百度百科
已經(jīng)不記得數(shù)學(xué)中的高階函數(shù)是個(gè)什么鬼了(請(qǐng)?jiān)徫沂莻€(gè)學(xué)渣~)。但是在Python中高階函數(shù)幾乎隨處可見(jiàn)攘乒。最經(jīng)典的莫過(guò)于map/reduce兩個(gè)函數(shù)了贤牛,這兩個(gè)函數(shù)后面講,我們先看一個(gè)簡(jiǎn)單的例子:
def f(x):
return x * x
def h(func, x):
return func(x) * func(x)
print(h(f, 2)) # 打印結(jié)果是: 16
這段代碼中函數(shù)h
就是一個(gè)高階函數(shù)持灰,因?yàn)樗牡谝粋€(gè)參數(shù)是一個(gè)函數(shù)(即接受一個(gè)函數(shù)作為輸入盔夜,滿(mǎn)足高階函數(shù)的第一個(gè)條件)。
再來(lái)看一個(gè):
def m(x):
def n():
return x * x
return n
print(m(2)()) # 打印結(jié)果是: 4
是的堤魁,你沒(méi)有看錯(cuò)喂链!在函數(shù)m
內(nèi)部定義了一個(gè)子函數(shù)n
,并且將該函數(shù)作為返回值返回妥泉。
當(dāng)我們調(diào)用m(2)
時(shí)椭微,返回值是函數(shù)n
,那么m(2)()
就是對(duì)函數(shù)n
的調(diào)用盲链。
如果還不理解蝇率,可以將print(m(2)())
拆成兩行:
sub_func = m(2)
print(sub_func())
這里還涉及了一個(gè)知識(shí)點(diǎn):
在Python中,對(duì)象和方法都是變量刽沾。
舉例說(shuō)明:
def say_hello(name):
print('Hello, %s' % name)
sh = say_hello # 將函數(shù)變量賦值給sh變量
sh('lovexiaov') # 打印結(jié)果是: Hello, lovexiaov
say_hello = 3 # 給函數(shù)變量賦值
say_hello('lovexiaov') # TypeError: 'int' object is not callable
閉包
說(shuō)到高階函數(shù)本慕,就不得不提閉包,先來(lái)看一下Python中閉包的定義:
如果在一個(gè)內(nèi)部函數(shù)里侧漓,對(duì)在外部作用域(但不是在全局作用域)的變量進(jìn)行引用锅尘,那么內(nèi)部函數(shù)就被認(rèn)為是閉包(closure)。
我們還是舉個(gè)例子:
def closure():
x = 5
def sub():
return x * x
return sub
如上布蔗,在內(nèi)部函數(shù)sub
中包含了對(duì)函數(shù)closure
中局部變量x
的引用藤违,這就是閉包。
匿名函數(shù)/lambda
在介紹高階函數(shù)的用處之前纵揍,還需要了解另一個(gè)概念顿乒,沒(méi)錯(cuò),就是匿名函數(shù)泽谨。Python語(yǔ)言支持使用?lambda 表達(dá)式作為匿名函數(shù)璧榄。
國(guó)際慣例特漩,代碼奉上:
def use_lambda():
return lambda x: x * x
print(use_lambda()(5)) # 打印結(jié)果是25
來(lái)看重點(diǎn)代碼lambda x: x * x
,這行代碼就是一個(gè)完整的函數(shù)犹菱。使用lambda
聲明該行代碼是一個(gè)lambda表達(dá)式拾稳,緊跟在后面的是函數(shù)的參數(shù),多個(gè)參數(shù)用逗號(hào),
分割腊脱;然后使用冒號(hào):
分割開(kāi)參數(shù)和函數(shù)體访得。該表達(dá)式拆解成普通的函數(shù)是這樣的:
def func(x):
return x * x
怎么樣,使用lambda表達(dá)式是不是讓代碼看起來(lái)整潔了許多陕凹,有強(qiáng)迫癥的同學(xué)們悍抑?
map函數(shù)
前面舉了很多高階函數(shù)的例子,那么使用高階函數(shù)到底有什么好處呢杜耙?是為了讓自己顯得高大上搜骡?這個(gè)問(wèn)題可以先留著,等看完下面的例子后自己找答案佑女。
map函數(shù)是Python中的內(nèi)置函數(shù)记靡,官方文檔定義(Python 3.5版本,不適合2.x版本)為:
map(function, iterable, ...)
Return an iterator that applies function to every item of iterable, yielding the results.
咳咳团驱,是時(shí)候展示我粗大的英語(yǔ)了摸吠。大致的意思是“function函數(shù)會(huì)作用于可迭代對(duì)象的每一個(gè)元素,生成結(jié)果嚎花,并返回一個(gè)迭代器”寸痢。至于yield
,我們可以暫時(shí)形象的理解為噎住
紊选,下面會(huì)進(jìn)行講解啼止。
現(xiàn)在假設(shè)我們要對(duì)一個(gè)數(shù)組中的每個(gè)元素求平方,并生成一個(gè)新數(shù)組返回兵罢,看代碼:
iter = map(lambda x: x * x, [1, 2, 3, 4])
for i in iter:
print('i : %d' % i)
代碼依然這么簡(jiǎn)潔献烦,而且意思很明確,雖然我們可以自己寫(xiě)函數(shù)實(shí)現(xiàn):
def get_square(l):
L = []
for i in l:
L.append(i * i)
return L
但是可讀性就差很多了卖词,在上一篇文章中我們就提到了Python的設(shè)計(jì)原則就是優(yōu)雅仿荆,明確,簡(jiǎn)單坏平,這里是不是一個(gè)很好的體現(xiàn)?
迭代器有一個(gè)特點(diǎn)锦亦,就是所有的迭代器對(duì)象都可以作為next()
內(nèi)置函數(shù)的參數(shù)調(diào)用舶替,每調(diào)用一次,就按角標(biāo)順序返回一個(gè)值杠园,還是用代碼講吧:
iter = map(lambda x: x * x, [1, 2, 3, 4])
print(next(iter)) # 打印值為:1
print(next(iter)) # 打印值為:4
print(next(iter)) # 打印值為:9
print(next(iter)) # 打印值為:16
print(next(iter)) # 拋出StopIteration 異常
怎么樣顾瞪,是不是有種被“噎住”的感覺(jué)啊,哈哈。
話(huà)說(shuō)回來(lái)陈醒,我們的Python語(yǔ)言也是一個(gè)“明明可以靠臉吃飯惕橙,卻偏要靠實(shí)力吃飯”的主,光優(yōu)雅钉跷,明確弥鹦,簡(jiǎn)單不夠,還必須得實(shí)用爷辙。下面我們來(lái)個(gè)更高級(jí)的:
r = map(lambda x, y: x + y, [1, 2, 3, 4], [5, 6, 7, 8])
print(r) # 打印結(jié)果:[6, 8, 10, 12]
0x02. 總結(jié)
在Python內(nèi)置函數(shù)和標(biāo)準(zhǔn)庫(kù)中彬坏,有不少都是高階函數(shù),合理利用這些函數(shù)可以使我們更便捷的開(kāi)發(fā)出功能強(qiáng)大的應(yīng)用膝晾。同時(shí)栓始,在我們的日常開(kāi)發(fā)中,合理使用高階函數(shù)會(huì)使我們的代碼更易于維護(hù)和有更高的可讀性血当。不要再猶豫了幻赚,開(kāi)始體驗(yàn)把!