python进行linux编程,Python之函数进阶
本節(jié)內(nèi)容
遞歸函數(shù)
嵌套函數(shù)與閉包
匿名函數(shù)
高階函數(shù)
內(nèi)置函數(shù)
總結(jié)
一、遞歸函數(shù)
函數(shù)是可以被調(diào)用的,且一個(gè)函數(shù)內(nèi)部可以調(diào)用其他函數(shù)。如果一個(gè)函數(shù)在內(nèi)部調(diào)用本身,這個(gè)函數(shù)就是一個(gè)遞歸函數(shù)。函數(shù)遞歸調(diào)用的過(guò)程與循環(huán)相似,而且理論上,所有的遞歸函數(shù)都可以寫(xiě)成循環(huán)的方式,但是遞歸函數(shù)的優(yōu)點(diǎn)是定義簡(jiǎn)單,邏輯清晰。遞歸和循環(huán)都是一個(gè)重復(fù)的操作的過(guò)程,這些重復(fù)性的操作必然是需要有一定的規(guī)律性的。另外,很明顯遞歸函數(shù)也需要一個(gè)結(jié)束條件,否則就會(huì)像死循環(huán)一樣遞歸下去,直到由于棧溢出而被終止(這個(gè)下面介紹)。
可見(jiàn),要實(shí)現(xiàn)一個(gè)遞歸函數(shù)需要確定兩個(gè)要素:
遞歸規(guī)律
結(jié)束條件
1. 實(shí)例:計(jì)算正整數(shù)n的階乘 n! = 1 * 2 * 3 * ... * n
循環(huán)實(shí)現(xiàn)
思路有兩個(gè):
從1乘到n,需要額外定義一個(gè)計(jì)數(shù)器存放n當(dāng)前的值
從n乘到1,無(wú)需額外定義計(jì)數(shù)器,直接對(duì)n進(jìn)行減1操作,直到n=0返回1結(jié)束
def fact(n):
if n == 0:
return 1
result = 1
while n >= 1:
result *= n
n -= 1
return result
遞歸實(shí)現(xiàn)
先來(lái)確定遞歸函數(shù)的兩個(gè)要素:
遞歸規(guī)律:n!=1 * 2 * 3 * ... * n = (n-1)! * n,也就是說(shuō)fact(n) = fact(n-1) * n,且n逐一減小
結(jié)束條件:當(dāng)n==0時(shí)返回1結(jié)束
def fact(n):
if n == 0:
return 1
return fact(n-1) * n
怎么樣?遞歸函數(shù)的實(shí)現(xiàn)方式是不是既簡(jiǎn)單、又清晰。
我們計(jì)算fact(5)的計(jì)算過(guò)程是這樣的:
===> fact(5)
===> 5 * fact(4)
===> 5 * (4 * fact(3))
===> 5 * (4 * (3 * fact(2)))
===> 5 * (4 * (3 * (2 * fact(1))))
===> 5 * (4 * (3 * (2 * 1)))
===> 5 * (4 * (3 * 2))
===> 5 * (4 * 6)
===> 5 * 24
===> 120
同理,要實(shí)現(xiàn)求1 + 2 + 3 + ... + n,可以這樣寫(xiě):
def fact(n):
if n == 1:
return 1
return fact(n-1) + n
2. 遞歸函數(shù)優(yōu)缺點(diǎn)
遞歸函數(shù)的優(yōu)點(diǎn):
定義簡(jiǎn)單、邏輯清晰。
遞歸函數(shù)的缺點(diǎn):
效率并不高且需要注意防止棧溢出。
其他特點(diǎn):
大家會(huì)發(fā)現(xiàn)上面實(shí)現(xiàn)的遞歸函數(shù)在運(yùn)算的過(guò)程中n是逐漸減小的,也就是說(shuō)問(wèn)題規(guī)模應(yīng)該是逐層減少的。
3. 遞歸特性總結(jié)
下面我們來(lái)總結(jié)寫(xiě)遞歸的特性:
必須有一個(gè)明確的結(jié)束條件
每次進(jìn)入更深一層的遞歸時(shí),問(wèn)題規(guī)模相比上次遞歸都應(yīng)有所減少
遞歸效率不高,遞歸層次過(guò)多會(huì)導(dǎo)致棧溢出。
因?yàn)樵谟?jì)算中,函數(shù)調(diào)用時(shí)通過(guò)棧(stack,特點(diǎn)是后進(jìn)先出--LIFO)這種數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的,每當(dāng)進(jìn)入一個(gè)函數(shù)調(diào)用,棧就會(huì)加一層棧針,每當(dāng)函數(shù)返回,棧就會(huì)減少一層棧針。由于棧的大小不是無(wú)限的,所有遞歸調(diào)用的次數(shù)過(guò)多,會(huì)導(dǎo)致棧溢出。關(guān)于堆棧的介紹可以看下這里:<>。
每種編程語(yǔ)言都對(duì)遞歸函數(shù)可遞歸的深度有限制(可以看看這里),有些是跟相應(yīng)內(nèi)存空間的分配有關(guān)(因?yàn)闂J窃趦?nèi)存空間中的),如Java。Python中對(duì)遞歸的深度限制默認(rèn)為1000,可以通過(guò)sys.getrecursionlimit()函數(shù)來(lái)獲取該值,超過(guò)這個(gè)深度會(huì)報(bào)錯(cuò):RecursionError: maximum recursion depth exceeded in comparison。當(dāng)然也可以通過(guò)sys.setrecursionlimit(n)來(lái)設(shè)置新的限制值。
二、嵌套函數(shù)與閉包
1. 嵌套函數(shù)
嵌套函數(shù)是指在函數(shù)內(nèi)部定義一個(gè)函數(shù),這些函數(shù)都遵循各自的作用域和生命周期規(guī)則。
來(lái)看個(gè)例子:
def outer():
level = 1
print('outer', level)
def inner():
print('inner', level)
inner()
調(diào)用outer函數(shù)outer(),輸出結(jié)果如下:
outer 1
inner 1
再來(lái)看個(gè)例子:
def outer():
level = 1
print('outer', level)
def inner():
level = 2
print('inner', level)
inner()
調(diào)用outer函數(shù)outer(),輸出結(jié)果如下:
outer 1
inner 2
嵌套函數(shù)查找變量的順序是:先查找自己函數(shù)體內(nèi)部是否包含該變量,如果包含則直接應(yīng)用,如果不包含則查找外層函數(shù)體內(nèi)是否包含該函數(shù),依次向外。
2. 閉包
首先要說(shuō)明一個(gè)問(wèn)題:函數(shù)名其實(shí)也是一個(gè)變量,我們通過(guò)def定義一個(gè)函數(shù)時(shí),實(shí)際上就是在定義一個(gè)變量,函數(shù)名就是變量名稱(chēng),函數(shù)體就是該變量的值。我們知道,變量是可以賦值給其他變量的,因此函數(shù)也是可以被當(dāng)做返回值返回的,并且可以賦值給其他變量。
def outer(x):
def inner(y):
print(x+y)
return inner
f1 = outer(10)
f2 = outer(20)
f1(100)
f2(100)
上面操作的執(zhí)行結(jié)果是:
110
120
我們知道局部變量的作用域是在定義它的函數(shù)體內(nèi)部,局部變量在函數(shù)執(zhí)行時(shí)進(jìn)行聲明,函數(shù)執(zhí)行完畢則會(huì)被釋放。上面也提到過(guò)了,函數(shù)也是一個(gè)變量,那么嵌套函數(shù)內(nèi)部定義的函數(shù)也是一個(gè)局部變量,也就是說(shuō)嵌套函數(shù)每調(diào)用一次,其內(nèi)部的函數(shù)都會(huì)被定義一次。因此,在上面的示例中
f1 = outer(10)
f2 = outer(20)
對(duì)于f1和f2而言,兩次調(diào)用嵌套函數(shù)outer并返回的內(nèi)部函數(shù)inner是不同的,且它們?nèi)〉降膞值也是不同的。從表面上來(lái)看f1和f2相當(dāng)于把x分別替換成了10和20:
def f1(y):
print(10+y)
def f2(y):
print(20+y)
但實(shí)際上不是這樣的,f1和f2還是這樣的:
def f1(y):
print(x+y)
def f2(y):
print(x+y)
f1和f2被調(diào)用時(shí),y的值是通過(guò)參數(shù)傳遞進(jìn)來(lái)的(100),而x還是個(gè)變量。inner函數(shù)會(huì)在自己的函數(shù)體內(nèi)部查找該局部變量x,發(fā)現(xiàn)沒(méi)找到,然后去查找它外層的函數(shù)局部��量x,找到了。這里好像出現(xiàn)問(wèn)題了,因?yàn)橹罢f(shuō)過(guò)了局部變量會(huì)在函數(shù)執(zhí)行結(jié)束后被釋放,那么f1和f2被調(diào)用時(shí)outer函數(shù)已經(jīng)執(zhí)行完了,理論上x(chóng)的值應(yīng)該被釋放了才對(duì)啊,為什么還能引用x的值?其實(shí),這就是閉包的作用。
閉包的定義
如果在一個(gè)內(nèi)部函數(shù)中,引用了外部非全局作用域中的變量,那么這個(gè)內(nèi)部函數(shù)就被認(rèn)為是閉包(closure)。
在一些語(yǔ)言中,在函數(shù)中可以(嵌套)定義另一個(gè)函數(shù)時(shí),如果內(nèi)部的函數(shù)應(yīng)用了外部函數(shù)的變量,則可能產(chǎn)生閉包。閉包可以用來(lái)在一個(gè)函數(shù)與一組“私有”變量之間創(chuàng)建關(guān)聯(lián)關(guān)系。在該內(nèi)部函數(shù)被多次調(diào)用的過(guò)程中,這些私有變量能夠保持其持久性。在支持將函數(shù)作為對(duì)象使用的編程語(yǔ)言中,一般都支持閉包,比如:Python、PHP、Javascript等。
閉包就是根據(jù)不同的配置信息得到不同的結(jié)果。專(zhuān)業(yè)解釋是:閉包(closure)是詞法閉包(Lexical Closure)的簡(jiǎn)稱(chēng),是引用了自由變量的函數(shù)。這個(gè)被引用的自由變量將和這個(gè)函數(shù)一同存在,即使已經(jīng)離開(kāi)了創(chuàng)造它的環(huán)境也不例外。所以,有另一種說(shuō)法認(rèn)為閉包是由函數(shù)和與其相關(guān)的應(yīng)用環(huán)境組合而成的實(shí)體。
閉包的工作原理
Ptyhon支持一種特性叫做函數(shù)閉包(function closres),它的工作原理是:在非全局(global)作用域(函數(shù))中定義inner函數(shù)時(shí),這個(gè)inner函數(shù)會(huì)記錄下外層函數(shù)的namespaces(外層函數(shù)作用域的locals,其中包括外層函數(shù)局部作用域中的所有變量),可以稱(chēng)作:定義時(shí)狀態(tài),inner函數(shù)可以通過(guò)__closure__(早期版本中為func_closure)這個(gè)屬性來(lái)獲得inner函數(shù)外層嵌套函數(shù)的namespaces。其實(shí)我們可以通過(guò)打印一個(gè)函數(shù)的__closesure__屬性值是否為None來(lái)判斷閉包是否發(fā)生。
閉包與裝飾器
其實(shí)裝飾器就是一種閉包,或者說(shuō)裝飾器是閉包的一種經(jīng)典應(yīng)用。區(qū)別在于,裝飾器的參數(shù)(配置信息)是一個(gè)函數(shù)或類(lèi),專(zhuān)門(mén)對(duì)類(lèi)或函數(shù)進(jìn)行加工、處理和功能增強(qiáng)。關(guān)于裝飾器,我們會(huì)在后面詳細(xì)介紹。
三、匿名函數(shù)
在Python中有兩種定義函數(shù)的方式:
通過(guò)def關(guān)鍵字定義的函數(shù):這是最常用的方式,前面已經(jīng)介紹過(guò)
通過(guò)lambda關(guān)鍵字定義的匿名函數(shù):這是本次要說(shuō)的主角
lambda作為一個(gè)關(guān)鍵字,作為引入表達(dá)式的語(yǔ)法。與def定義的函數(shù)相比較而言,lambda是單一的表達(dá)式,而不是語(yǔ)句塊。也就是說(shuō),我們僅僅能夠在lambda中封裝有限的業(yè)務(wù)邏輯(通常只是一個(gè)表達(dá)式),這樣設(shè)計(jì)的目的在于:讓lambda純粹為了編寫(xiě)簡(jiǎn)單的函數(shù)(通常稱(chēng)為小函數(shù))而設(shè)計(jì),def則專(zhuān)注于處理更大的業(yè)務(wù)。
1. 匿名函數(shù)的定義
語(yǔ)法:
lambda argument1, argument2, ... argumentN :expression using argments
冒號(hào)左邊是函數(shù)的參數(shù),冒號(hào)右邊是一個(gè)整合參數(shù)并計(jì)算返回值的表達(dá)式。
實(shí)例:定義一個(gè)求兩個(gè)數(shù)之和的函數(shù)
def函數(shù)
def add(x, y):
return x + y
lambda函數(shù)
lambda x, y: x+y
2. 匿名函數(shù)的調(diào)用方式:
調(diào)用方式1:匿名函數(shù)也是一個(gè)函數(shù)對(duì)象,可以將匿名函數(shù)賦值給一個(gè)變量,然后通過(guò)在這個(gè)變量后加上一對(duì)小括號(hào)來(lái)調(diào)用:
add = lambda x, y: x+y
sum = add(1, 2)
調(diào)用方式2:直接在lambda函數(shù)后加上一堆小括號(hào)調(diào)用:
sum = (lambda x, y: x+y)(1, 3)
3. 匿名函數(shù)的特性:
函數(shù)體只能包含一個(gè)表達(dá)式
不能有return語(yǔ)句(表達(dá)式的值就是它的返回值)
參數(shù)個(gè)數(shù)不限,可以有0個(gè)、1個(gè)或多個(gè)
4. 什么時(shí)候用匿名函數(shù)
從上面提到的“匿名函數(shù)的調(diào)用方式”來(lái)看,匿名函數(shù)貌似沒(méi)有什么卵用,反而可讀性更差了。那么匿名函數(shù)在Python中存在的意義是什么呢?匿名函數(shù)一般應(yīng)用于函數(shù)式編程中,在Python中通常是指與高階函數(shù)的配合使用--把匿名函數(shù)當(dāng)做高階函數(shù)的參數(shù)來(lái)使用,下面的高階函數(shù)實(shí)例中會(huì)用到。
四、高階函數(shù)
我們上面已經(jīng)提到過(guò):函數(shù)名也是變量,函數(shù)名就是指向函數(shù)的變量。并且我們已經(jīng)知道:變量是可以作為參數(shù)傳遞給函數(shù)的。由此,我們得出一個(gè)結(jié)論:函數(shù)是一個(gè)接受另外一個(gè)函數(shù)作為參數(shù)的,而這種函數(shù)就稱(chēng)為高階函數(shù)(Higher-order function)。
1. 自定義高階函數(shù)
我們來(lái)自定義一個(gè)高階函數(shù),這個(gè)函數(shù)用于求兩個(gè)數(shù)的和,同時(shí)接收一個(gè)函數(shù)用于在求和之前對(duì)兩個(gè)數(shù)值參數(shù)做一些額外的處理(如:取絕對(duì)值、求平方或其他任意操作)
def nb_add(x, y, f):
return f(x) + f(y)
其中x,y是用于求和的兩個(gè)數(shù)值參數(shù),f是對(duì)x,y進(jìn)行處理的函數(shù)。我們?cè)囍冉of傳遞一個(gè)內(nèi)置的abs(取絕對(duì)值)函數(shù),也就是說(shuō)先對(duì)x和y分別取絕對(duì)值,然后再相加:
result = nb_add(10, -20, abs)
print(result)
運(yùn)行結(jié)果是:30
我們來(lái)自定義一個(gè)求平方的方法,然后傳遞給f試試:
def pow2(x):
return pow(x, 2)
result = nb_add(10, -20, pow2)
print(result)
輸出結(jié)果是:500
我們發(fā)現(xiàn)上面定義的pow2(x)函數(shù)的函數(shù)體只有一個(gè)表達(dá)式,因此我們完全可以不單獨(dú)定義該函數(shù)而使用匿名函數(shù)來(lái)實(shí)現(xiàn),這樣可以使diamante變得更簡(jiǎn)潔:
def nb_add(x, y, f):
return f(x) + f(y)
result = nb_add(10, 20, lambda x: pow(x, 2))
print(result)
2. 常見(jiàn)內(nèi)置高階函數(shù)
Python內(nèi)置了一些非常有用的高階函數(shù),下面我們來(lái)看看常見(jiàn)的幾個(gè):
map函數(shù)
map(function, iterable, ...)
map函數(shù)的參數(shù)說(shuō)明:
map函數(shù)接收兩類(lèi)參數(shù):函數(shù)和可迭代對(duì)象(Iterable)
第一個(gè)參數(shù)是函數(shù),后面的參數(shù)都是可迭代對(duì)象。
處理函數(shù)的參數(shù)個(gè)數(shù)需要與傳入的可迭代對(duì)象參數(shù)的個(gè)數(shù)對(duì)應(yīng),否則會(huì)報(bào)錯(cuò)。
如果傳入的可迭代對(duì)象參數(shù)有多個(gè),且每個(gè)iterable元素?cái)?shù)量不相等時(shí),結(jié)果中的元素個(gè)數(shù)與最短的那個(gè)iterable的元素個(gè)數(shù)一致。
map函數(shù)的作用是:
將傳入的函數(shù)依次作用到可迭代對(duì)象的每個(gè)元素,并把結(jié)果作為新的迭代器對(duì)象(Iterator)返回(Python2.x中會(huì)直接返回一個(gè)列表)。
實(shí)例1:計(jì)算給定列表中的每個(gè)元素的平方值并放回一個(gè)新的列表
def pow2(x):
return x * x
L = [1, 2, 3, 4, 5, 6]
list1 = list(map(pow2, L))
print(list1)
輸出結(jié)果為:[1, 4, 9, 16, 25, 36]
上面已經(jīng)演示過(guò),pow2()可以直接使用匿名函數(shù):
L = [1, 2, 3, 4, 5, 6]
list1 = list(map(lambda x: pow(x, 2), L))
print(list1)
可見(jiàn)map函數(shù)作為高階函數(shù),事實(shí)上是把運(yùn)算規(guī)則抽象了,因此,我們不僅可以計(jì)算簡(jiǎn)單的f(x)=x*x,還可以計(jì)算任意復(fù)雜的函數(shù)。
實(shí)例2:計(jì)算兩個(gè)序列中對(duì)應(yīng)元素的和并保存至一個(gè)新的列表中
L = [1, 2, 3, 4, 5, 6]
T = (7, 8, 9, 10)
list1 = list(map(lambda x, y: x+y, L, T))
print(list1)
輸出結(jié)果為:[8, 10, 12, 14]
reduce函數(shù)
這里需要說(shuō)明一下:reduce函數(shù)在Python 2.x中跟map函數(shù)一樣都是Python內(nèi)置函數(shù),Python 3.x中已經(jīng)被轉(zhuǎn)移到functools模塊了。
reduce(function, sequence, initializer=None)
reduce函數(shù)的參數(shù)說(shuō)明:
接收一個(gè)函數(shù)參數(shù)、一個(gè)序列參數(shù)和一個(gè)可選的initalizer參數(shù)
如果可選參數(shù)initializer被提供,則相當(dāng)于把它作為sequence的一個(gè)元素插入sequence的首部
reduce函數(shù)的作用是:
把一個(gè)函數(shù)作用在指定的序列上,這個(gè)函數(shù)必須接收兩個(gè)參數(shù),然后把計(jì)算結(jié)果繼續(xù)和序列的下一個(gè)元素做累計(jì)計(jì)算,最終返回一個(gè)結(jié)果。簡(jiǎn)單來(lái)講,就是對(duì)一個(gè)序列中的元素做聚合運(yùn)算。
實(shí)例1:計(jì)算指定數(shù)列中所有元素的和
from functools import reduce
L = [1, 2, 3, 4, 5]
sum1 = reduce(lambda x, y: x + y, L)
print(sum1)
sum2 = reduce(lambda x, y: x + y, L, 6)
print(sum2)
輸出結(jié)果為:
15
21
這個(gè)過(guò)程相當(dāng)于:(((1 + 2) + 3) + 4) + 5
實(shí)例2:將數(shù)字字符串轉(zhuǎn)成int
from functools import reduce
def fn(x, y):
return int(x)*10 + int(y)
num = reduce(lambda x, y: int(x)*10 + y, '12345')
print(num)
也可以封裝成一個(gè)函數(shù):
from functools import reduce
def str2int(s):
return reduce(lambda x, y: int(x)*10 + int(y), s)
num = str2int('12345')
print(num)
也可以先通過(guò)map函數(shù)將字符串中的字符轉(zhuǎn)成int,然后再通過(guò)reduce進(jìn)行運(yùn)算:
from functools import reduce
def str2int(s):
def char2num(c):
return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[c]
return reduce(lambda x, y: x*10 + y, map(char2num, s))
num = str2int('12345')
print(num)
其實(shí)char2sum也可以用匿名函數(shù)來(lái)實(shí)現(xiàn),但是可讀性不太好。另外我舉這個(gè)例子的本義不是為了單純的演示map/reduce/匿名函數(shù)的使用,而是想說(shuō)明嵌套函數(shù)與高階函數(shù)綜合使用的場(chǎng)景,這在某些場(chǎng)景下可以使代碼邏輯變得更清晰。
filter函數(shù)
filter(function, iterable)
filter函數(shù)的參數(shù)說(shuō)明:
filter函數(shù)接收一個(gè)函數(shù)參數(shù)和一個(gè)可迭代對(duì)象參數(shù),��數(shù)參數(shù)可以為None
函數(shù)的返回值(True或False)用于判斷可迭代對(duì)象的當(dāng)前元素是否要保留
filter函數(shù)的作用是:
用于過(guò)濾可迭代對(duì)象,具體過(guò)程是:把傳入的函數(shù)依次作用于可迭代對(duì)象的每個(gè)元素,如果函數(shù)返回值為T(mén)ure則保留該元素,如果返回值為False則丟棄該元素,并最終把保留的元素作為一個(gè)iterator(迭代器)返回。如果function是None,則根據(jù)可迭代對(duì)象各元素的真值測(cè)試結(jié)果決定是否保留該元素。
與Python內(nèi)置的filter函數(shù)作用剛好相反的函數(shù)是itertools.filterfalse(function, sequence),它用于過(guò)濾出序列中通過(guò)function函數(shù)計(jì)算結(jié)果為False的元素。
實(shí)例1:分別打印出指定列表中的奇數(shù)和偶數(shù)
from itertools import filterfalse
L = [1, 2, 3, 4, 5, 6, 7, 8, 9]
odd_num = list(filter(lambda x: x % 2 == 1, L))
even_num = list(filterfalse(lambda x: x%2 == 1, L))
print('奇數(shù):', odd_num)
print('偶數(shù):', even_num)
輸出結(jié)果:
奇數(shù): [1, 3, 5, 7, 9]
偶數(shù): [2, 4, 6, 8]
實(shí)例2:刪除序列中的空字符串
L = ['ABC', '', 'DEF', ' ', '1233', None]
list1 = list(filter(None, L))
print(list1)
輸出結(jié)果為:['ABC', 'DEF', ' ', '1233']
由于第4個(gè)由3個(gè)空白字符組成的字符串的真值測(cè)試結(jié)果為T(mén)rue,因此它還是會(huì)被保留。被看來(lái)還是需要傳遞個(gè)函數(shù)參數(shù)才行:
L = ['ABC', '', 'DEF', ' ', '1233', None]
list1 = list(filter(lambda s: s and s.strip(), L))
print(list1)
輸出結(jié)果:['ABC', 'DEF', '1233']
sorted函數(shù)
sorted(iterable[, key][, reverse])
sorted函數(shù)的參數(shù)說(shuō)明:
sorted函數(shù)可以接收一個(gè)可迭代對(duì)象iterable作為必選參數(shù),還可以接收兩個(gè)可選參數(shù)key和reverse,但是這兩個(gè)可選參數(shù)如果要提供的話,需要作為關(guān)鍵字參數(shù)進(jìn)行傳遞;
參數(shù)key接收的是一個(gè)函數(shù)名,該函數(shù)用來(lái)實(shí)現(xiàn)自定義排序;如,要按照絕對(duì)值大小進(jìn)行排序:key=abs
參數(shù)reverse接收的是一個(gè)布爾值:如果reverse=Ture,表示倒敘排序,如果reverse=False,表示正序排序;reverse默認(rèn)值為False
關(guān)于參數(shù)key的進(jìn)一步說(shuō)明: 排序的核心是比較兩個(gè)元素的大小。如果要比較的是兩個(gè)數(shù)字,我們可以直接比較;如果是字符串,也可以按照ASCII碼的大小進(jìn)行比較。但是,如果要比較的元素是兩個(gè)序列或dict等復(fù)雜數(shù)據(jù)呢?這時(shí),我們可能需要指定一個(gè)計(jì)算“用于比較的值”的運(yùn)算規(guī)則,比如我們指定取兩個(gè)dict中的某個(gè)共同的key對(duì)應(yīng)的值來(lái)進(jìn)行比較,又比如我們指定用將兩個(gè)字符串都轉(zhuǎn)換為小寫(xiě)或者大寫(xiě)后的結(jié)果值進(jìn)行比較。其實(shí)說(shuō)簡(jiǎn)單點(diǎn),參數(shù)key這個(gè)函數(shù)作用是:計(jì)算/獲取用來(lái)進(jìn)行比較的值。如果我們需要自定義這個(gè)函數(shù)時(shí),需要注意該函數(shù)應(yīng)該有一個(gè)參數(shù),這個(gè)參數(shù)接收的就是可迭代對(duì)象中每個(gè)元素的值。
sorted函數(shù)的作用是:
對(duì)可迭代對(duì)象iterable中的元素進(jìn)行排序,并將排序結(jié)果作為一個(gè)新的list返回。
實(shí)例1:數(shù)字列表排序
list1 = sorted([10, 9, -21, 13, -30])
list2 = sorted([10, 9, -21, 13, -30], key=abs)
list3 = sorted([10, 9, -21, 13, -30], key=abs, reverse=True)
print(list1)
print(list2)
print(list3)
輸出結(jié)果:
[-30, -21, 9, 10, 13]
[9, 10, 13, -21, -30]
[-30, -21, 13, 10, 9]
實(shí)例2:字符串列表排序
list1 = sorted(['how', 'What', 'check', 'Zero'])
list2 = sorted(['how', 'What', 'check', 'Zero'], key=lower)
list3 = sorted(['how', 'What', 'check', 'Zero'], key=lower, reverse=True)
print(list1)
print(list2)
print(list3)
輸出結(jié)果:
['What', 'Zero', 'check', 'how']
['check', 'how', 'What', 'Zero']
['Zero', 'What', 'how', 'check']
實(shí)例3:tuple列表排序
假設(shè)我們用一組tuple表示姓名和年齡,然后用sorted()函數(shù)分別按姓名升序和年齡降序進(jìn)行排序:
def sort_by_name(t):
return t[0]
def sort_by_age(t):
return t[1]
L = [('Tom', 18), ('Jerry', 15), ('Peter', 16), ('John', 20)]
list1 = sorted(L, key=sort_by_name)
list2 = sorted(L, key=sort_by_age, reverse=True)
print('sort by name asc: ', list1)
print('sort by age desc: ', list2)
輸出結(jié)果:
sort by name asc: [('Jerry', 15), ('John', 20), ('Peter', 16), ('Tom', 18)]
sort by age desc: [('John', 20), ('Tom', 18), ('Peter', 16), ('Jerry', 15)]
實(shí)例4:字典內(nèi)容排序
對(duì)字典排序的方法有很多中,但核心思想都是一樣的:把dict中的key或value或item分離出來(lái)放到一個(gè)list中,然后在對(duì)這個(gè)list進(jìn)行排序,從而間接實(shí)現(xiàn)對(duì)dict的排序。
D = {'Tom': 18, 'Jerry': 15, 'Peter': 16, 'John': 20}
list1 = sorted(D.items(), key=lambda d: d[0])
list2 = sorted(D.items(), key=lambda d: d[1], reverse=True)
print('sort by key asc:', list1)
print('sort by value desc:', list2)
輸出結(jié)果:
sort by key asc: [('Jerry', 15), ('John', 20), ('Peter', 16), ('Tom', 18)]
sort by value desc: [('John', 20), ('Tom', 18), ('Peter', 16), ('Jerry', 15)]
五、內(nèi)置函數(shù)
Python解釋器有許多內(nèi)置的函數(shù)和類(lèi)型,有一些之前已經(jīng)用到過(guò),比如:
數(shù)學(xué)函數(shù):abs()、max()、min()、pow()、sum()
類(lèi)型轉(zhuǎn)換函數(shù):int()、float()、str()、bool()、list()、tuple()、dict()、set()
進(jìn)制轉(zhuǎn)換函數(shù):bin()、oct()、hex()
高階函數(shù):map()、filter()、sorted()
打開(kāi)文件用的函數(shù):的open()
輸入與輸出函數(shù):input()、raw_input()、print()
獲取對(duì)象內(nèi)存地址的函數(shù):id()
這些函數(shù)我們?cè)谥暗奈恼轮谢径佳菔玖?#xff0c;不在此贅述。關(guān)于他們的詳細(xì)說(shuō)明以及其它內(nèi)置函數(shù)的使用可以參考下面給出的列表及官方文檔連接地址。
Python 3相對(duì)于Python 2的內(nèi)置函數(shù)有些變動(dòng):
新增了一些內(nèi)置方法,如:ascii()、bytes()、exec()
刪除了一些內(nèi)置方法, 如:cmp()、execfile()
移動(dòng)了一些內(nèi)置方法,如:reduce()被移動(dòng)到了functools模塊下
修改了一些內(nèi)置方法,如:sorted()函數(shù)在Python 3.5的文檔中么有再提到cmp參數(shù)了(貌似用不到這個(gè)參數(shù))
Python 3中的高階函數(shù)還有一個(gè)比較大的改變,如map()和filter()在Python 2中是直接返回一個(gè)列表(list),而在Python 3中是返回一個(gè)迭代器(Iterator)。
Python 3.5內(nèi)置函數(shù)列表(官方文檔地址)
Python 2.7內(nèi)置函數(shù)列表(官方文檔地址)
六、總結(jié)
這里講了分別講了Python中函數(shù)的一些高級(jí)應(yīng)用,如果能把這些內(nèi)容整合起來(lái)靈活運(yùn)用會(huì)發(fā)揮很大的威力。比如后面要說(shuō)到的裝飾就是高階函數(shù)、嵌套函數(shù)以及閉包的一個(gè)典型應(yīng)用。
總結(jié)
以上是生活随笔為你收集整理的python进行linux编程,Python之函数进阶的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: red hat linux 7.1 使用
- 下一篇: linux eclipse go插件,E