python中的函數(shù)

1.函數(shù)的介紹

為什么要有函數(shù)?因為在平時寫代碼時,如果沒有函數(shù)的話,那么將會出現(xiàn)很多重復的代碼,這樣代碼重用率就比較低。。。并且這樣的代碼維護起來也是很有難度的,為了解決這些問題,就出現(xiàn)了函數(shù),用來將一些經(jīng)常出現(xiàn)的代碼進行封裝,這樣就可以在任何需要調(diào)用這段代碼的地方調(diào)用這個函數(shù)就行了。

函數(shù)的定義:函數(shù)是指將一組語句的集合通過一個名字(函數(shù)名)封裝起來,要想執(zhí)行這個函數(shù),只需調(diào)用其函數(shù)名即可

特性:

a.代碼重用

b.保持一致性

c.可擴展性

2.函數(shù)的創(chuàng)建

在python中函數(shù)定義的格式如下:


函數(shù)的調(diào)用使用 :函數(shù)名(實參) 就可以調(diào)用函數(shù)了。

函數(shù)名的命名規(guī)則和變量的命名規(guī)則一樣:

1、函數(shù)名必須以下劃線或字母開頭,可以包含任意字母、數(shù)字或下劃線的組合。不能使用任何的標點符號;

2、函數(shù)名是區(qū)分大小寫的。

3、函數(shù)名不能是保留字。

形參和實參的區(qū)別:

函數(shù)在定義的時候,函數(shù)名后面的括號中可以添加參數(shù),這些參數(shù)就叫做形參,形參:顧名思義就是形式參數(shù),只是一個代號。

實參是在調(diào)用函數(shù)的時候函數(shù)名后面的括號中的參數(shù),形參和實參需要一一對應起來,否則調(diào)用函數(shù)會報錯。

3.函數(shù)參數(shù)及返回值

前面提到函數(shù)的形參和實參要一一對應,那么參數(shù)對應有如下幾種:

1、必須參數(shù)

2、關鍵字參數(shù)

3、默認參數(shù)

4、不定長參數(shù) *args

5、不定長參數(shù) **kwargs

1.必須參數(shù):

必須參數(shù)必須以對應的關系一個一個傳遞進入函數(shù),函數(shù)調(diào)用時傳遞的實參必須和函數(shù)定義時的形參一一對應,不能多也不能少,順序也得一致。

舉個栗子:


2.關鍵字參數(shù)

關鍵字參數(shù)是實參里面的概念,在調(diào)用函數(shù)的時候聲明某個參數(shù)是屬于某個關鍵字的。使用關鍵字參數(shù)允許函數(shù)調(diào)用時參數(shù)的順序與聲明時不一致,因為 Python 解釋器能夠用參數(shù)名匹配參數(shù)值。

舉個栗子:


3.默認參數(shù)

默認參數(shù)是在函數(shù)聲明的時候,可以給某個參數(shù)指定默認值,這樣的參數(shù)叫做默認值參數(shù)。如果在調(diào)用函數(shù)的時候,默認參數(shù)沒有接收到對應的實參,那么就會將默認值賦值給這個參數(shù)。



4.不定長參數(shù) *args

在python里面,函數(shù)在聲明的時候,參數(shù)中可以使用(*變量名)的方式來接受不確定長度的參數(shù),但是在python里面大家約定俗成使用*args接受不定長參數(shù),這樣在調(diào)用函數(shù)的時候傳遞的參數(shù)就可以是不定長度的了。args接受了不定長參數(shù)之后,將這些參數(shù)放到一個tuple里面,可以通過訪問args來獲取這些不定長參數(shù)。




5.不定長參數(shù) **kwargs

但是上面的args只能接收未命名的參數(shù),那假如有類似于關鍵字參數(shù)的不定長參數(shù)該怎么辦呢?python里面使用(**變量名)來接收不定長的命名變量參數(shù)。同樣,python里面也約定俗成使用**kwargs接收不定長命名參數(shù)。kwargs接收了不定長參數(shù)之后,將這些參數(shù)放到一個字典里面,可以通過key獲取到相應的參數(shù)值。


介紹完了這些參數(shù)之后,接下來要介紹的是關于這些參數(shù)混合使用的情況:

假如一個函數(shù)使用了上面所有種類的參數(shù),那該怎么辦?為了不產(chǎn)生歧義,python里面規(guī)定了假如有多種參數(shù)混合的情況下,遵循如下的順序使用規(guī)則:

def f(必須參數(shù),默認參數(shù),*args,**kwargs):

????pass

如果同時存在args和kwargs的話,args在左邊

默認參數(shù)在必須參數(shù)的右邊,在*args的左邊

關鍵字參數(shù)的位置不固定(ps:關鍵字參數(shù)也不在函數(shù)定義的時候確定)

那么,假如有一個列表想要傳遞進入一個不定長的未命名參數(shù)的函數(shù)中去,可以在該列表前面加上*實現(xiàn),同理如果想傳遞一個字典進入不定長命名參數(shù)的函數(shù)中去,可以在該字典前面加上**

舉個栗子:

deff(*args,**kwargs):

????print(args)

????for i in kwargs:

print("%s:%s"%(i,kwargs[i]))

f(*[1,2,3],**{"a":1,"b":2})

函數(shù)的返回值

要想獲取函數(shù)的執(zhí)行結果,就可以用return語句把結果返回

注意:

函數(shù)在執(zhí)行過程中只要遇到return語句,就會停止執(zhí)行并返回結果,也可以理解為 return 語句代表著函數(shù)的結束 如果未在函數(shù)中指定return,那這個函數(shù)的返回值為None

return多個對象,解釋器會把這多個對象組裝成一個元組作為一個一個整體結果輸出。

4.LEGB作用域

python中的作用域分4種情況:

L:local,局部作用域,即函數(shù)中定義的變量;

E:enclosing,嵌套的父級函數(shù)的局部作用域,即包含此函數(shù)的上級函數(shù)的局部作用域,但不是全局的;

G:globa,全局變量,就是模塊級別定義的變量;

B:built-in,系統(tǒng)固定模塊里面的變量,比如int, bytearray等。 搜索變量的優(yōu)先級順序依次是:作用域局部>外層作用域>當前模塊中的全局>python內(nèi)置作用域,也就是LEGB。

local和enclosing是相對的,enclosing變量相對上層來說也是local。

在Python中,只有模塊(module),類(class)以及函數(shù)(def、lambda)才會引入新的作用域,其它的代碼塊(如if、try、for等)不會引入新的作用域。

global關鍵字

當內(nèi)部作用域想修改外部作用域的變量時,就要用到global和nonlocal關鍵字了,當修改的變量是在全局作用域(global作用域)上的,就要使用global先聲明一下。

nonlocal關鍵字

global關鍵字聲明的變量必須在全局作用域上,不能嵌套作用域上,當要修改嵌套作用域(enclosing作用域,外層非全局作用域)中的變量怎么辦呢,這時就需要nonlocal關鍵字。

小結

變量查找順序:LEGB,作用域局部>外層作用域>當前模塊中的全局>python內(nèi)置作用域;

只有模塊、類、及函數(shù)才能引入新作用域;

對于一個變量,內(nèi)部作用域先聲明就會覆蓋外部變量,不聲明直接使用,就會使用外部作用域的變量;

內(nèi)部作用域要修改外部作用域變量的值時,全局變量要使用global關鍵字,嵌套作用域變量要使用nonlocal關鍵字。nonlocal是python3新增的關鍵字,有了這個 關鍵字,就能完美的實現(xiàn)閉包了。

5.特殊函數(shù)

遞歸函數(shù)定義:遞歸函數(shù)就是在函數(shù)內(nèi)部調(diào)用自己

有時候解決某些問題的時候,邏輯比較復雜,這時候可以考慮使用遞歸,因為使用遞歸函數(shù)的話,邏輯比較清晰,可以解決一些比較復雜的問題。但是遞歸函數(shù)存在一個問題就是假如遞歸調(diào)用自己的次數(shù)比較多的話,將會使得計算速度變得很慢,而且在python中默認的遞歸調(diào)用深度是1000層,超過這個層數(shù)將會導致“爆棧”。。。所以,在可以不用遞歸的時候建議盡量不要使用遞歸。

遞歸函數(shù)的優(yōu)點:定義簡單,邏輯清晰。理論上,所有的遞歸函數(shù)都可以寫成循環(huán)的方式,但循環(huán)的邏輯不如遞歸清晰。

遞歸特性:

1、必須有一個明確的結束條件

2、每次進入更深一層遞歸時,問題規(guī)模相比上次遞歸都應有所減少

3、遞歸效率不高,遞歸層次過多會導致棧溢出(在計算機中,函數(shù)調(diào)用是通過棧(stack)這種數(shù)據(jù)結構實現(xiàn)的,每當進入一個函數(shù)調(diào)用,棧就會加一層棧幀,每當函數(shù)返 回,棧就會減一層棧幀。由于棧的大小不是無限的,所以,遞歸調(diào)用的次數(shù)過多,會導致棧溢出。)

6.函數(shù)式編程

關于函數(shù)式編程,我理解的也不是很深,但是python中有4個比較重要的內(nèi)置函數(shù),組合起來使用有時候能大大提高編程效率。

1、filter(function, sequence)

str=['a','b','c','d']

def fun1(s):

if s !='a':

return s

ret=filter(fun1,str)

print(list(ret))# ret是一個迭代器對象

對sequence中的item依次執(zhí)行function(item),將執(zhí)行結果為True的item做成一個filter object的迭代器返回。可以看作是過濾函數(shù)。

2、 map(function, sequence)

str=[1,2,'a','b']

def fun2(s):

return s+"alvin"

ret=map(fun2,str)

print(ret)# map object的迭代器

print(list(ret))# ['aalvin', 'balvin', 'calvin', 'dalvin']

對sequence中的item依次執(zhí)行function(item),將執(zhí)行結果組成一個map object迭代器返回. map也支持多個sequence,這就要求function也支持相應數(shù)量的參數(shù)輸入:

def add(x,y):

return x+y

print(list(map(add,range(10),range(10))))##[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

3、 reduce(function, sequence, starting_value)

from functools import reduce

def add1(x,y):

return x+y

print(reduce(add1,range(1,101)))## 4950 (注:1+2+...+99)

print(reduce(add1,range(1,101),20))## 4970 (注:1+2+...+99+20)

對sequence中的item順序迭代調(diào)用function,如果有starting_value,還可以作為初始值調(diào)用.

4 、lambda

普通函數(shù)與匿名函數(shù)的對比:

#普通函數(shù)

def add(a,b):

return a+b

print add(2,3)

#匿名函數(shù)

add=lambda a,b : a+b

print add(2,3)

#========輸出===========

5

5

匿名函數(shù)的命名規(guī)則,用lamdba 關鍵字標識,冒號(:)左側表示函數(shù)接收的參數(shù)(a,b) ,冒號(:)右側表示函數(shù)的返回值(a+b)。

因為lamdba在創(chuàng)建時不需要命名,所以,叫匿名函數(shù)

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容