Python基础(五)--函数
目錄
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Python基礎(chǔ)(五)--函數(shù)
1 函數(shù)的作用
1.1 函數(shù)定義與調(diào)用
1.2 函數(shù)的作用
1.3 空語(yǔ)句
2 參數(shù)與返回值
2.1 函數(shù)的參數(shù)
2.2 函數(shù)的返回值
2.3 返回多個(gè)值
3 參數(shù)的默認(rèn)值
3.1 可選參數(shù)
3.2 參數(shù)的默認(rèn)值
4 位置參數(shù)與關(guān)鍵字參數(shù)
4.1 關(guān)鍵詞做參數(shù)
5 可變參數(shù)
5.1 兩種可變參數(shù)
5.2 打包與拆包
6 參數(shù)傳遞
7 命名空間與作用域
7.1 命名空間
7.2 作用域
7.3 LEGB原則
8 Lamabda表達(dá)式
9 遞歸
9.1 什么是遞歸
9.2 循環(huán)與遞歸
9.3 遞歸的深度
10 高階函數(shù)
11 函數(shù)描述
11.1 函數(shù)說(shuō)明文檔
11.2 函數(shù)注解
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Python基礎(chǔ)(五)--函數(shù)
1 函數(shù)的作用
1.1 函數(shù)定義與調(diào)用
函數(shù)的概念:函數(shù)是具有一定功能的代碼塊,該代碼塊可以重復(fù)的執(zhí)行。
函數(shù)的定義方式如下:
? ? def 函數(shù)名(參數(shù)列表):
? ? ? ? ?函數(shù)體
函數(shù)的調(diào)用:當(dāng)定義了一個(gè)函數(shù)即定義了一個(gè)功能后,我們使用該功能就稱之為函數(shù)的調(diào)用。當(dāng)調(diào)用函數(shù)時(shí),程序會(huì)跳轉(zhuǎn)到函數(shù)定義處執(zhí)行函數(shù)體,當(dāng)函數(shù)體執(zhí)行完畢后程序流程會(huì)返回給函數(shù)的調(diào)用端,繼續(xù)執(zhí)行調(diào)用后的語(yǔ)句。
# 函數(shù)的定義 def print_triangle():for i in range(9):for j in range(i+1,9):print("*",end=" ")print() # 函數(shù)的調(diào)用 print_triangle()1.2 函數(shù)的作用
(1)避免代碼重復(fù),實(shí)現(xiàn)代碼的復(fù)用
(2)對(duì)功能進(jìn)行詳細(xì)的劃分,在需要使用功能時(shí),就可以調(diào)用該函數(shù)。
1.3 空語(yǔ)句
在程序設(shè)計(jì)時(shí),我們就可以先把程序劃分成若干個(gè)功能,具體的實(shí)現(xiàn)可以后續(xù)再完成。此時(shí),我們就可以使用pass來(lái)進(jìn)行占位。pass表示空語(yǔ)句,用在函數(shù)中用來(lái)進(jìn)行占位。pass也可以放在選擇與循環(huán)體中。
# 空函數(shù) def vacancy():pass2 參數(shù)與返回值
2.1 函數(shù)的參數(shù)
在函數(shù)定義時(shí)提供的參數(shù),稱為形式參數(shù);在函數(shù)調(diào)用是提供的參數(shù)稱為實(shí)參;在函數(shù)調(diào)用的過(guò)程中,實(shí)際參數(shù)會(huì)賦值給形式參數(shù)。
參數(shù)的作用:功能是由函數(shù)本身所決定的,但是功能具有一定的細(xì)節(jié),具體的細(xì)節(jié)通過(guò)參數(shù)進(jìn)行調(diào)整控制。
# 函數(shù)的定義 def print_triangle(length):for i in range(length+1):for j in range(i+1,length+1):print("*",end=" ")print() # 函數(shù)的調(diào)用 print_triangle(2) print_triangle(3)2.2 函數(shù)的返回值
函數(shù)也是可以具有返回值,該返回值會(huì)返回給函數(shù)的調(diào)用端。語(yǔ)法上,使用return來(lái)實(shí)現(xiàn)。遇到return,函數(shù)就會(huì)終止執(zhí)行,同時(shí)將return后的值返回給調(diào)用端
當(dāng)調(diào)用函數(shù)時(shí),可以近似的認(rèn)為是函數(shù)的返回值替換掉了函數(shù)的調(diào)用。
如果在函數(shù)內(nèi)沒(méi)有顯式使用return返回值,則返回值為None。
def add(x,y):return x + yprint("不會(huì)執(zhí)行") # 函數(shù)的返回值替換掉了函數(shù)的調(diào)用 result = add(1,1) print(result) # 函數(shù)總有一個(gè)返回值,如果沒(méi)有顯示調(diào)用return,默認(rèn)為None def add1(x,y):sum = x + y result1 = add(1,1) print(result1)2.3 返回多個(gè)值
在函數(shù)中,當(dāng)執(zhí)行到return語(yǔ)句時(shí),函數(shù)就會(huì)終止執(zhí)行,返回給函數(shù)的調(diào)用端,這就是說(shuō),return之后的語(yǔ)句不會(huì)再執(zhí)行。因此,函數(shù)體中不能通過(guò)執(zhí)行多個(gè)return,返回多個(gè)值。可以通過(guò)將多個(gè)值放入元組(列表或字典)中,從而返回多個(gè)值。
# 返回多個(gè)值。可以通過(guò)將多個(gè)值放入元組(列表或字典)中,元組比較合適,因?yàn)樵M不能修改 def operation(x,y):return (x + y,x - y,x * y,x / y) print(operation(2,2))3 參數(shù)的默認(rèn)值
3.1 可選參數(shù)
如果一個(gè)參數(shù)含有默認(rèn)值,則該參數(shù)就稱為一個(gè)可選參數(shù),可有可無(wú)。
如果顯式傳遞了該函數(shù),則該參數(shù)的值就是我們傳遞的值,如果沒(méi)有則是該參數(shù)的默認(rèn)值
3.2 參數(shù)的默認(rèn)值
(1)參數(shù)默認(rèn)值的要求
如果形參含有默認(rèn)值,則在函數(shù)定義時(shí),含有默認(rèn)值的形參一定要定義在不含默認(rèn)值的形參之后。
這是因?yàn)?#xff0c;如果形參含有默認(rèn)值,則意味著,該參數(shù)是一個(gè)可選參數(shù),在函數(shù)調(diào)用時(shí),可以選擇性的進(jìn)行傳值。如果允許含有默認(rèn)值的形參定義在不含默認(rèn)值的形參前面,就會(huì)造成混淆。
# 函數(shù)的定義 def print_triangle(length,char="*"):for i in range(length+1):for j in range(i+1,length+1):print(char,end=" ")print() # 函數(shù)的調(diào)用 print_triangle(3) print_triangle(3,"@")(2)含有默認(rèn)值的意義
①可以另函數(shù)的功能變得簡(jiǎn)單;
②可以兼容之前的程序
(3)注意事項(xiàng)
形參默認(rèn)值,其只是在聲明的一刻進(jìn)行求值,并且僅求值一次。因此,當(dāng)使用可變類型作為參數(shù)默認(rèn)值時(shí),可能會(huì)帶來(lái)意外的結(jié)果。
在Python中,函數(shù)也是對(duì)象,我們給形參增加的默認(rèn)值,也是保存在函數(shù)中。我們可以通過(guò)函數(shù)對(duì)象的__defaults__屬性來(lái)獲取函數(shù)形參的默認(rèn)值。__defaults__返回的是一個(gè)元組類型,包含函數(shù)定義時(shí),形參所有的默認(rèn)值。
# 注意:函數(shù)的形式參數(shù)的默認(rèn)值是在函數(shù)定義的時(shí)候解析器計(jì)算,不是調(diào)用的時(shí)候計(jì)算,因此參數(shù)的默認(rèn)值只計(jì)算1次 num = 6 def add(a,b=num):print(a+b) num = 10 add(6)# 當(dāng)默認(rèn)值是可變對(duì)象時(shí),要特別注意,每次調(diào)用都會(huì)改變 def fun(a=[]):a.append(10)print(a) fun() fun()# 獲取函數(shù)的默認(rèn)值,返回的是一個(gè)元組 print(fun.__defaults__)4 位置參數(shù)與關(guān)鍵字參數(shù)
位置參數(shù)與關(guān)鍵字參數(shù)是針對(duì)實(shí)際參數(shù)而言的。
在調(diào)用函數(shù)時(shí),如果函數(shù)定義了形式參數(shù),則我們需要在調(diào)用時(shí),傳遞相應(yīng)的實(shí)際參數(shù)(如果形參具有默認(rèn)值可不傳遞),形式為按順序,一一對(duì)應(yīng)的方式。即第一個(gè)實(shí)參傳遞給第一個(gè)形參,第二個(gè)實(shí)參傳遞給第二個(gè)形參……,這種對(duì)位傳遞的實(shí)際參數(shù)為位置參數(shù)。
除了位置參數(shù)之外,我們還可以使用關(guān)鍵字參數(shù)。所謂關(guān)鍵字參數(shù),就是在調(diào)用函數(shù)時(shí),顯式指定“參數(shù)名=參數(shù)值”的形式,即指定要給哪一個(gè)形參傳遞值。
在調(diào)用函數(shù)時(shí),可以混合使用位置參數(shù)與關(guān)鍵字參數(shù)。
4.1 關(guān)鍵詞做參數(shù)
優(yōu)點(diǎn):(1)增加程序的可讀性
(2)可以不考慮傳遞的順序
(3)當(dāng)多個(gè)形參存在默認(rèn)值時(shí),關(guān)鍵字參數(shù)能夠指定賦值給哪個(gè)形參。
注意:
(1)位置參數(shù)必須在關(guān)鍵字參數(shù)前面
(2)同一個(gè)參數(shù)不能傳遞多次
(3)關(guān)鍵字參數(shù)的順序可以顛倒,但是提供的參數(shù)名必須存在
def add(a,b,c):pass # 位置參數(shù)傳遞值 add(1,2,3) # 關(guān)鍵字參數(shù)傳遞值 add(a=1,b=2,c=3) # 同一個(gè)參數(shù)只能傳遞一次,否則出錯(cuò) # add(1,2,c=3,b=5) 報(bào)錯(cuò) # 位置參數(shù)必須位于關(guān)鍵字參數(shù)前 # add(b=2,2,3) 報(bào)錯(cuò)強(qiáng)制使用關(guān)鍵字參數(shù):
了能夠增強(qiáng)程序的可讀性,同時(shí)實(shí)現(xiàn)編程風(fēng)格的一致性,函數(shù)的定義者可以使用“*”語(yǔ)法,來(lái)限制“*”后面的所有參數(shù)必須都是以關(guān)鍵字參數(shù)的形式傳遞。強(qiáng)制使用關(guān)鍵字往往針對(duì)的是具有默認(rèn)值的參數(shù),但從語(yǔ)法的角度講,對(duì)于不含默認(rèn)值的參數(shù),也是可以的。
# 強(qiáng)制使用關(guān)鍵字參數(shù) ,使用* def add(a,*,b=5):pass # add(1,2) TypeError: add() takes 1 positional argument but 2 were given # 正確寫法為 add(1,b=2)5 可變參數(shù)
5.1 兩種可變參數(shù)
(1)兩種可變參數(shù)
在定義函數(shù)時(shí),我們可以定義可變參數(shù)(形式參數(shù)),所謂可變參數(shù),即可以接收不定數(shù)量的實(shí)際參數(shù)。可變參數(shù)有兩種形式:①位置可變參數(shù)(*);②關(guān)鍵字可變參數(shù)(**)
(2)參數(shù)打包
函數(shù)調(diào)用時(shí),位置可變參數(shù)(形參)可以用來(lái)接收所有未匹配的位置參數(shù)(實(shí)參),而關(guān)鍵字可變參數(shù)(形參)可以用來(lái)接收所有未匹配的關(guān)鍵字參數(shù)(實(shí)參)。在函數(shù)調(diào)用過(guò)程中,所有未匹配的位置參數(shù)會(huì)打包成一個(gè)元組,而所有未匹配的關(guān)鍵字參數(shù)會(huì)打包成一個(gè)字典。
# *v位置可變參數(shù),**kv關(guān)鍵字可變參數(shù) def fun(*v, **kv):print(type(v))print(v)print(type(kv))print(kv) fun(1,2,3,a=11,b=22)注意:
①可變參數(shù)只能接收未匹配的(剩下的)實(shí)際參數(shù),如果實(shí)際參數(shù)已經(jīng)匹配某形式參數(shù),則不會(huì)由可變參數(shù)接收。
②在參數(shù)位置上,關(guān)鍵字可變參數(shù)必須位于函數(shù)參數(shù)列表的最后。
③在位置可變參數(shù)后面定義的參數(shù),將自動(dòng)成為關(guān)鍵字參數(shù)。
④位置可變參數(shù)與關(guān)鍵字可變參數(shù)各自最多只能定義一個(gè)。
(3)位置可變參數(shù)
def sum(*value):
(4)關(guān)鍵字可變參數(shù)
在接收一些可選的選項(xiàng),設(shè)置時(shí),對(duì)于選項(xiàng)較多時(shí),如果將每個(gè)選項(xiàng)都用一個(gè)關(guān)鍵字參數(shù)來(lái)接收時(shí),會(huì)顯得函數(shù)定義特別龐大,此時(shí),就可以使用一個(gè)關(guān)鍵字可變參數(shù)來(lái)實(shí)現(xiàn)。
# 位置可變參數(shù),可以用來(lái)接收任意數(shù)量的位置參數(shù),在參數(shù)前面加* # 在函數(shù)調(diào)用過(guò)程中,會(huì)執(zhí)行打包操作,位置可變參數(shù)是一個(gè)元組類型 def sum(*a):print(type(a))sum = 0for i in a:sum += ireturn sum result = sum(1,2,3) print(result)# 關(guān)鍵字可變參數(shù),可以用來(lái)接收任意數(shù)量的關(guān)鍵字參數(shù),在參數(shù)前面加上** # 在函數(shù)調(diào)用過(guò)程中,會(huì)執(zhí)行打包操作,關(guān)鍵字參數(shù)打包成字典類型 def sum(**kv):print(type(kv))print(kv) sum(a=1,b="abc",c=[1,2,3])# 萬(wàn)能參數(shù)列表,可變關(guān)鍵字參數(shù)必須位于參數(shù)列表最后 def omnipotent(*a,**kv):pass5.2 打包與拆包
拆包:將序列類型拆分為多個(gè)位置參數(shù),或者將字典類型拆分成多個(gè)關(guān)鍵字參數(shù)。
其實(shí),在進(jìn)行平時(shí)賦值時(shí),也會(huì)隱式發(fā)生元組的打包與拆包操作。
# 拆包 def sum(a,b,c):print(a,b,c) # 序列拆包 param = (1,2,3) sum(*param)# 字典拆包,分解為若干關(guān)鍵字參數(shù)的形式 param2 = {"a":"aaa","b":"bbb","c":"ccc"} sum(**param2)6 參數(shù)傳遞
同過(guò)參數(shù)傳遞,我們可以使形式參數(shù)與實(shí)參綁定相同的對(duì)象,通過(guò)形參可以改變實(shí)參所綁定的數(shù)據(jù)對(duì)象。
注意:不能通過(guò)改變形參所綁定的對(duì)象,進(jìn)而影響實(shí)參。實(shí)參所綁定的對(duì)象不會(huì)進(jìn)行更改,即在函數(shù)調(diào)用前,實(shí)參綁定到哪個(gè)對(duì)象,在函數(shù)調(diào)用之后,實(shí)參依然會(huì)綁定原來(lái)的對(duì)象。
def fun(a):a.append(100) li = [1,2,3] fun(li) print(li)def fun(a):a = [] li = [1,2,3] fun(li) print(li)7 命名空間與作用域
7.1 命名空間
命名空間:可以認(rèn)為是保存命名的一個(gè)容器,當(dāng)定義變量,函數(shù),類等結(jié)構(gòu)時(shí),相關(guān)的名稱就保存在相應(yīng)的命名空間中。根據(jù)名稱在當(dāng)前模塊(文件)中定義的位置,根據(jù)命名可以將名稱分為兩類:局部命名空間(定義在函數(shù)內(nèi)的名稱(函數(shù)的參數(shù),變量,嵌套函數(shù)等))和全局命名空間(定義在函數(shù)、類外的名稱(處于當(dāng)前模塊的頂級(jí))。)
命名空間可以有多個(gè),不同的命名空間可以保存相同的名稱,彼此之間不會(huì)受到干擾
命名空間可以分為如下幾類:
①內(nèi)建命名空間:保存內(nèi)建的名稱。例如,print,sum等內(nèi)建函數(shù)。內(nèi)建命名空間在Python解釋器啟動(dòng)時(shí)就會(huì)創(chuàng)建,直到程序運(yùn)行結(jié)束。
②全局命名空間:保存當(dāng)前模塊(文件)中出現(xiàn)在頂層位置的名稱。例如:全局變量,頂層函數(shù)等。全局命名空間與模塊相關(guān),在讀取模塊定義時(shí)創(chuàng)建,直到程序運(yùn)行結(jié)束。
③局部命名空間:保存局部名稱。例如,局部變量,函數(shù)參數(shù),嵌套函數(shù)等。局部命名空間在函數(shù)執(zhí)行時(shí)創(chuàng)建,在函數(shù)執(zhí)行結(jié)束后銷毀。
所以我們定義的函數(shù),變量等其名稱屬于哪個(gè)命名空間,由其定義的位置決定。對(duì)于變量,定義的位置就是變量第一次賦值的位置。對(duì)于函數(shù),定義的位置就是def出現(xiàn)的時(shí)刻。
# 全局變量 x = 6 # 全局函數(shù) def overall():# 局部變量y = 1# python函數(shù)可以嵌套# 局部函數(shù)def inner():pass7.2 作用域
作用域,就是命名空間的有效區(qū)域。在作用域內(nèi),我們可以直接訪問(wèn)命名空間中的名稱。
①內(nèi)建命名空間,作用域?yàn)樗心K(文件)。在任何模塊(文件)中均可直接訪問(wèn)內(nèi)建命名空間內(nèi)的名稱。
②全局命名空間,作用域?yàn)楫?dāng)前模塊(文件)。在當(dāng)前模塊(文件)中可直接訪問(wèn)全局命名空間內(nèi)的名稱,在其他模塊(文件)中,需要先導(dǎo)入該模塊,然后才能訪問(wèn)(模塊導(dǎo)入的內(nèi)容后面介紹)。
③局部命名空間,作用域?yàn)楫?dāng)前函數(shù),在函數(shù)內(nèi)可訪問(wèn)局部命名空間內(nèi)的名稱,在函數(shù)外則無(wú)法訪問(wèn)。
7.3 LEGB原則
在訪問(wèn)名稱時(shí),會(huì)根據(jù)LEGB的順序來(lái)搜索名稱,即搜索順序?yàn)長(zhǎng)?->?E?->?G?->?B。描述如下:
①L(Local):本地作用域,即包含所訪問(wèn)名稱的最小作用域(當(dāng)前函數(shù)的局部命名空間)。
②E(Enclosing)外圍作用域,當(dāng)函數(shù)嵌套時(shí)會(huì)存在這種情況,即訪問(wèn)外層函數(shù)的作用域,如果沒(méi)有找到,并且外層函數(shù)依然還有外層函數(shù)(函數(shù)多層嵌套),則會(huì)繼續(xù)搜索更外層的函數(shù),直到頂層函數(shù)位置(對(duì)應(yīng)外層函數(shù)的局部命名空間)
③G(Global)全局作用域,當(dāng)前模塊的作用域(全局命名空間)。
④B(Build-in)內(nèi)建作用域,所有內(nèi)建的名稱(內(nèi)建命名空間)。
在讀取名稱值時(shí):如果該變量在當(dāng)前作用域沒(méi)有發(fā)現(xiàn),則會(huì)按照LEGB的方式依次進(jìn)行查找,以先找到的為準(zhǔn)。如果到最后也沒(méi)有找到,則會(huì)產(chǎn)生NameError錯(cuò)誤。
為名稱賦值時(shí):會(huì)在程序執(zhí)行處的最小作用域內(nèi)尋找變量,如果變量存在,則修改該變量的綁定,如果該變量不存在,則不會(huì)再按照LEGB的順序查找,而是在當(dāng)前作用域的命名空間中,新建名稱,并綁定所賦予的值。這也就是說(shuō),我們無(wú)法修改其他命名空間中名稱的綁定。
注意:命名空間有什么在函數(shù)解析的時(shí)候已經(jīng)確定下來(lái)了,盡管命名空間是在調(diào)用的時(shí)候才創(chuàng)建但是該有什么沒(méi)有什么在函數(shù)解析的時(shí)候已經(jīng)能夠決定好的,不會(huì)等到一步步執(zhí)行的時(shí)候才確定下來(lái)
# 全局變量 x = 6 # 全局函數(shù) def overall():x = 8print(x) overall() print(x)def overall2():# 命名空間中存在哪些名稱不是在執(zhí)行的時(shí)候一點(diǎn)一點(diǎn)創(chuàng)建出來(lái)的,是在解析編譯的時(shí)候已經(jīng)能夠決定有哪些。在解析的時(shí)候已經(jīng)發(fā)現(xiàn)有x了,那就認(rèn)為會(huì)在當(dāng)前的這個(gè)命名空間中去創(chuàng)建這個(gè)x,所以在print的時(shí)候就認(rèn)為是這個(gè)局部的命名空間,而不是全局的命名空間x。因?yàn)閜rint訪問(wèn)x的時(shí)候發(fā)現(xiàn)還沒(méi)有被賦值(沒(méi)有綁定任何有效的對(duì)象),所以報(bào)錯(cuò)# print(x) 報(bào)錯(cuò):UnboundLocalError: local variable 'x' referenced before assignmentx = 8 overall2()def overall3():# x = x + 1 報(bào)錯(cuò):UnboundLocalError: local variable 'x' referenced before assignment 原因如上訪問(wèn)x的時(shí)候x還沒(méi)有被賦值pass overall3()刪除命名空間是:當(dāng)刪除名稱時(shí),其表現(xiàn)行為與為名稱賦值是一致的。即只能刪除當(dāng)前作用域的名稱,而不能刪除外層作用域的名稱。
nonlocal與global:當(dāng)期望對(duì)外部作用域的名稱進(jìn)行修改時(shí),可以使用nonlocal或者global。
注意:nonlocal指定的名稱不存在,會(huì)產(chǎn)生錯(cuò)誤,而global指定的名稱不存在則不會(huì)產(chǎn)生錯(cuò)誤,但是該名稱也不會(huì)自動(dòng)創(chuàng)建,如果訪問(wèn)該名稱,依然會(huì)產(chǎn)生錯(cuò)誤。
# 內(nèi)建命名空間的優(yōu)先級(jí)最低,所以我們自己定義的名稱一定會(huì)覆蓋命名空間的名稱 id = 6 print(id) # 在當(dāng)前命名空間下無(wú)法修改或刪除其他命名空間的名稱,如果希望修改其他命名空間的 # 名稱,可以借助global或nonlocal del id print(id(8)) # 全局命名空間 def overall():# 進(jìn)行聲明,表示我們要操作的是全局命名空間,而不是當(dāng)前命名空間global aa = 66 overall() print(a)def overall2():b = 88def inner():# 進(jìn)行聲明,表示我們要操作的是外圍命名空間中的名稱,而不是當(dāng)前局部命名空間中的名稱nonlocal bb = 99inner()print(b) overall2() # 注意:global指定的名稱如果不存在,不會(huì)產(chǎn)生錯(cuò)誤,而nonlocal指定的名稱不存在會(huì)產(chǎn)生錯(cuò)誤 def fun():global no_existdef inner():# nonlocal no_exist 指定的命名空間不存在報(bào)錯(cuò)passinner() fun()8 Lamabda表達(dá)式
對(duì)于函數(shù)而言,函數(shù)名也是一個(gè)名稱,該名稱綁定函數(shù)對(duì)象。因此,我們也可以像變量那樣,對(duì)函數(shù)名進(jìn)行相應(yīng)操作,如:①將函數(shù)名賦值給一個(gè)變量②將函數(shù)名作為實(shí)際參數(shù)傳遞給其他函數(shù)③函數(shù)名可以作為另外一個(gè)函數(shù)的返回值
可以使用Lambda表達(dá)式來(lái)創(chuàng)建函數(shù),Lambda表達(dá)式的語(yǔ)法為:
? ? lambda [參數(shù)]: 表達(dá)式
參數(shù)是可選的,表達(dá)式的結(jié)果值,就是函數(shù)的返回值。lambda表達(dá)式的函數(shù)體僅能存在一條語(yǔ)句,故lambda表達(dá)式適用于功能簡(jiǎn)單的函數(shù)。也因?yàn)閘ambda表達(dá)式創(chuàng)建的函數(shù)沒(méi)有名字,因此也稱為匿名函數(shù)。
# 變量與函數(shù)都是一個(gè)名稱,函數(shù)名可以像變量名那樣操作 def print_hello():print("hello") print_hello() # 函數(shù)名可以進(jìn)行賦值,賦值給一個(gè)變量 a = print_hello # 通過(guò)a調(diào)用函數(shù) a() def fun(b):return abs(b) li = [-5,-2,6] # 將函數(shù)名作為實(shí)際參數(shù)傳遞給其他函數(shù) li.sort(key=fun) print(li) # 函數(shù)名可以作為另外一個(gè)函數(shù)的返回值 def outer():c= 6def inner():passreturn inner d = outer()# lambda表達(dá)式用來(lái)定義匿名函數(shù),lambda [參數(shù)]:返回值表達(dá)式 li.sort(key=lambda x : abs(x)) print(li) def lam():return lambda x : x + 29 遞歸
9.1 什么是遞歸
遞歸,就是一個(gè)函數(shù)直接或者間接調(diào)用自身的過(guò)程。
函數(shù)如果無(wú)條件的調(diào)用自身,這是沒(méi)有意義的,最終也會(huì)導(dǎo)致超過(guò)最大遞歸深度而產(chǎn)生錯(cuò)誤。因此,我們必須能夠找出,讓遞歸終止的條件。
遞歸,可以分為遞推與回歸。遞推:就是解決問(wèn)題,逐層的進(jìn)行推理,得出遞歸的終止點(diǎn)。回歸:則是利用剛才遞推取得終止點(diǎn)的條件,再一層層返回,最終取得答案的過(guò)程。
9.2 循環(huán)與遞歸
循環(huán)與遞歸具有一定的相似度,二者往往可以實(shí)現(xiàn)相同的效果。理論上,能夠通過(guò)循環(huán)解決的問(wèn)題,使用遞歸也能夠?qū)崿F(xiàn)。
從思想的角度看,循環(huán)是重復(fù)性的執(zhí)行一件相同或者相似的事情,進(jìn)而得出結(jié)果。而遞歸則是將問(wèn)題分解為更小的問(wèn)題,直到該問(wèn)題能夠解決,然后再由最小問(wèn)題的答案,逐步回歸,從而解決更大的問(wèn)題,最終解決整個(gè)問(wèn)題的過(guò)程。
遞歸的默認(rèn)深度為1000。
# 循環(huán)求和 def loop(a):sum = 0for i in range(1,a+1):sum += ireturn sum print(loop(10)) # 遞歸求和 def recur(b):if b == 1:return 1else:return b + recur(b-1) print(recur(10))9.3 遞歸的深度
遞歸的默認(rèn)深度為1000。遞歸的默認(rèn)深度,應(yīng)該將其理解為最大函數(shù)調(diào)用限制。
# 遞歸的深度 import sys # 返回遞歸的最大深度 print(sys.getrecursionlimit()) # 設(shè)置遞歸的最大深度 sys.setrecursionlimit(3) def first():two() def two():third() def third():four() def four():pass first()10 高階函數(shù)
如果一個(gè)函數(shù)的接收另外一個(gè)函數(shù)作為參數(shù),或者該函數(shù)將另外一個(gè)函數(shù)作為返回值,則這樣的函數(shù)稱為高階函數(shù)。
常用的高階函數(shù)有:
(1)map(func, *iterables)
def sum(a):return a + a # map的第一個(gè)參數(shù)為一個(gè)函數(shù),第二個(gè)參數(shù)為一個(gè)可迭代的對(duì)象 # 對(duì)可迭代對(duì)象中的每一個(gè)元素,調(diào)用一次函數(shù)(即第一個(gè)參數(shù)),將該元素傳入獲得返回值,將所有返回值作為一個(gè)可迭代對(duì)象返回 m = map(sum,[6,8,10]) print(m) for i in m:print(i,end=" ") print() # 上面的函數(shù)可以用lambda m1 = map(lambda a : a+a, [6,8,10]) for i in m1:print(i,end=" ") print() # map可用列表推導(dǎo)式代替,所以使用頻率較低 li = [6,8,10] print([i + i for i in li])(2)filter(function or None, iterable)
# filter,第一個(gè)參數(shù)為一個(gè)函數(shù),該函數(shù)具有一個(gè)參數(shù),第二個(gè)參數(shù)為可迭代對(duì)象 # 對(duì)可迭代對(duì)象中的每一個(gè)元素,調(diào)用一次函數(shù),將元素傳入,獲得返回值,將所有返回值為True的元素保留,返回一個(gè)可迭代對(duì)象 f = filter(lambda a : a > 3,[1,2,3,4,5,6]) for i in f:print(i,end=" ") print() # filter也可用列表推導(dǎo)式代替,所以使用頻率較低 li=[1,2,3,4,5,6] print([i for i in li if i>3])(3)reduce(function, sequence[, initial]) -> value
從Python3.0起,reduce不在是內(nèi)置函數(shù)(Python2是內(nèi)置函數(shù)),而是將其遷移到了functools模塊中。
# reduce,第一個(gè)參數(shù)為一個(gè)函數(shù),具有兩個(gè)參數(shù),第二個(gè)參數(shù)為可迭代對(duì)象,第三個(gè)參數(shù)為初始值(可選) import functools li = list(range(1,6)) print(functools.reduce(lambda x,y:x+y,li))11 函數(shù)描述
11.1 函數(shù)說(shuō)明文檔
說(shuō)明文檔,就相當(dāng)于是函數(shù)的使用說(shuō)明書,在文檔中可以用來(lái)說(shuō)明函數(shù)的功能,參數(shù),返回值類型以及相關(guān)注意事項(xiàng),使用示例等。要為函數(shù)編寫說(shuō)明文檔,可以在函數(shù)體的上方,使用字符串進(jìn)行標(biāo)記。按照慣例,作為說(shuō)明文檔的字符串使用三個(gè)雙引號(hào)界定,并且第一行為函數(shù)的一個(gè)簡(jiǎn)要說(shuō)明,接下來(lái)是一個(gè)空行,然后是函數(shù)的具體說(shuō)明。
def fun():
? ? ?"""這里是函數(shù)的簡(jiǎn)要說(shuō)明。
?
? ? ?這是是函數(shù)的具體功能說(shuō)明。(注意存在一個(gè)空行)
? ? ? """
? ? ?# 函數(shù)語(yǔ)句
注釋內(nèi)容,則解釋器會(huì)忽略,但是,作為函數(shù)文檔,我們可以通過(guò)函數(shù)的__doc__屬性獲取這些說(shuō)明,方便我們進(jìn)行查看。同時(shí),我們使用help函數(shù)來(lái)獲取幫助時(shí),返回的就是函數(shù)的說(shuō)明文檔信息。
11.2 函數(shù)注解
在Python中,變量是沒(méi)有類型的,對(duì)于函數(shù)來(lái)說(shuō),無(wú)法像C或Java語(yǔ)言那樣,只要觀看函數(shù)的定義,就可以輕松的確定函數(shù)的參數(shù)與返回值類型。為了彌補(bǔ)這種不足,使代碼更具有可讀性與易用性,我們可以使用函數(shù)注解來(lái)進(jìn)行標(biāo)注,顯式指定函數(shù)參數(shù)或返回值的類型。
def add(a: int, b: int=3) ->int:
參數(shù)的說(shuō)明是在參數(shù)后面加上一個(gè):然后給出參數(shù)的類型。根據(jù)慣例,:與其后的類型使用一個(gè)空格分隔。返回值說(shuō)明是在參數(shù)列表的)后,使用->指出。
可以使用函數(shù)對(duì)象的__annotations__屬性獲取函數(shù)的注解信息。該屬性是一個(gè)字典類型。
?
?
?
?
?
?
?
總結(jié)
以上是生活随笔為你收集整理的Python基础(五)--函数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: RDD持久化、广播、累加器
- 下一篇: 安装Python第三方库的常用方法和注意