1.函數(shù)的介紹
為什么要有函數(shù)?因?yàn)樵谄綍r(shí)寫(xiě)代碼時(shí)疚顷,如果沒(méi)有函數(shù)的話锁保,那么將會(huì)出現(xiàn)很多重復(fù)的代碼,這樣代碼重用率就比較低叛买。。蹋订。并且這樣的代碼維護(hù)起來(lái)也是很有難度的率挣,為了解決這些問(wèn)題,就出現(xiàn)了函數(shù)露戒,用來(lái)將一些經(jīng)常出現(xiàn)的代碼進(jìn)行封裝椒功,這樣就可以在任何需要調(diào)用這段代碼的地方調(diào)用這個(gè)函數(shù)就行了。
函數(shù)的定義:函數(shù)是指將一組語(yǔ)句的集合通過(guò)一個(gè)名字(函數(shù)名)封裝起來(lái)智什,要想執(zhí)行這個(gè)函數(shù)动漾,只需調(diào)用其函數(shù)名即可
特性:
a.代碼重用
b.保持一致性
c.可擴(kuò)展性
2.函數(shù)的創(chuàng)建
在python中函數(shù)定義的格式如下:
函數(shù)的調(diào)用使用 :函數(shù)名(實(shí)參) 就可以調(diào)用函數(shù)了。
函數(shù)名的命名規(guī)則和變量的命名規(guī)則一樣:
1荠锭、函數(shù)名必須以下劃線或字母開(kāi)頭旱眯,可以包含任意字母、數(shù)字或下劃線的組合。不能使用任何的標(biāo)點(diǎn)符號(hào)删豺;
2础爬、函數(shù)名是區(qū)分大小寫(xiě)的。
3吼鳞、函數(shù)名不能是保留字看蚜。
形參和實(shí)參的區(qū)別:
函數(shù)在定義的時(shí)候,函數(shù)名后面的括號(hào)中可以添加參數(shù)赔桌,這些參數(shù)就叫做形參供炎,形參:顧名思義就是形式參數(shù),只是一個(gè)代號(hào)疾党。
實(shí)參是在調(diào)用函數(shù)的時(shí)候函數(shù)名后面的括號(hào)中的參數(shù)音诫,形參和實(shí)參需要一一對(duì)應(yīng)起來(lái),否則調(diào)用函數(shù)會(huì)報(bào)錯(cuò)雪位。
3.函數(shù)參數(shù)及返回值
前面提到函數(shù)的形參和實(shí)參要一一對(duì)應(yīng)竭钝,那么參數(shù)對(duì)應(yīng)有如下幾種:
1、必須參數(shù)
2雹洗、關(guān)鍵字參數(shù)
3香罐、默認(rèn)參數(shù)
4、不定長(zhǎng)參數(shù) *args
5时肿、不定長(zhǎng)參數(shù) **kwargs
1.必須參數(shù):
必須參數(shù)必須以對(duì)應(yīng)的關(guān)系一個(gè)一個(gè)傳遞進(jìn)入函數(shù)庇茫,函數(shù)調(diào)用時(shí)傳遞的實(shí)參必須和函數(shù)定義時(shí)的形參一一對(duì)應(yīng),不能多也不能少螃成,順序也得一致旦签。
舉個(gè)栗子:
2.關(guān)鍵字參數(shù)
關(guān)鍵字參數(shù)是實(shí)參里面的概念,在調(diào)用函數(shù)的時(shí)候聲明某個(gè)參數(shù)是屬于某個(gè)關(guān)鍵字的寸宏。使用關(guān)鍵字參數(shù)允許函數(shù)調(diào)用時(shí)參數(shù)的順序與聲明時(shí)不一致宁炫,因?yàn)?Python 解釋器能夠用參數(shù)名匹配參數(shù)值。
舉個(gè)栗子:
3.默認(rèn)參數(shù)
默認(rèn)參數(shù)是在函數(shù)聲明的時(shí)候氮凝,可以給某個(gè)參數(shù)指定默認(rèn)值羔巢,這樣的參數(shù)叫做默認(rèn)值參數(shù)。如果在調(diào)用函數(shù)的時(shí)候覆醇,默認(rèn)參數(shù)沒(méi)有接收到對(duì)應(yīng)的實(shí)參朵纷,那么就會(huì)將默認(rèn)值賦值給這個(gè)參數(shù)。
4.不定長(zhǎng)參數(shù) *args
在python里面永脓,函數(shù)在聲明的時(shí)候,參數(shù)中可以使用(*變量名)的方式來(lái)接受不確定長(zhǎng)度的參數(shù)鞋仍,但是在python里面大家約定俗成使用*args接受不定長(zhǎng)參數(shù)常摧,這樣在調(diào)用函數(shù)的時(shí)候傳遞的參數(shù)就可以是不定長(zhǎng)度的了。args接受了不定長(zhǎng)參數(shù)之后,將這些參數(shù)放到一個(gè)tuple里面落午,可以通過(guò)訪問(wèn)args來(lái)獲取這些不定長(zhǎng)參數(shù)谎懦。
5.不定長(zhǎng)參數(shù) **kwargs
但是上面的args只能接收未命名的參數(shù),那假如有類似于關(guān)鍵字參數(shù)的不定長(zhǎng)參數(shù)該怎么辦呢溃斋?python里面使用(**變量名)來(lái)接收不定長(zhǎng)的命名變量參數(shù)界拦。同樣,python里面也約定俗成使用**kwargs接收不定長(zhǎng)命名參數(shù)梗劫。kwargs接收了不定長(zhǎng)參數(shù)之后享甸,將這些參數(shù)放到一個(gè)字典里面,可以通過(guò)key獲取到相應(yīng)的參數(shù)值梳侨。
介紹完了這些參數(shù)之后蛉威,接下來(lái)要介紹的是關(guān)于這些參數(shù)混合使用的情況:
假如一個(gè)函數(shù)使用了上面所有種類的參數(shù),那該怎么辦走哺?為了不產(chǎn)生歧義蚯嫌,python里面規(guī)定了假如有多種參數(shù)混合的情況下,遵循如下的順序使用規(guī)則:
def f(必須參數(shù),默認(rèn)參數(shù),*args,**kwargs):
????pass
如果同時(shí)存在args和kwargs的話丙躏,args在左邊
默認(rèn)參數(shù)在必須參數(shù)的右邊择示,在*args的左邊
關(guān)鍵字參數(shù)的位置不固定(ps:關(guān)鍵字參數(shù)也不在函數(shù)定義的時(shí)候確定)
那么,假如有一個(gè)列表想要傳遞進(jìn)入一個(gè)不定長(zhǎng)的未命名參數(shù)的函數(shù)中去晒旅,可以在該列表前面加上*實(shí)現(xiàn)对妄,同理如果想傳遞一個(gè)字典進(jìn)入不定長(zhǎng)命名參數(shù)的函數(shù)中去,可以在該字典前面加上**
舉個(gè)栗子:
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í)行結(jié)果敢朱,就可以用return語(yǔ)句把結(jié)果返回
注意:
函數(shù)在執(zhí)行過(guò)程中只要遇到return語(yǔ)句剪菱,就會(huì)停止執(zhí)行并返回結(jié)果,也可以理解為 return 語(yǔ)句代表著函數(shù)的結(jié)束 如果未在函數(shù)中指定return,那這個(gè)函數(shù)的返回值為None
return多個(gè)對(duì)象拴签,解釋器會(huì)把這多個(gè)對(duì)象組裝成一個(gè)元組作為一個(gè)一個(gè)整體結(jié)果輸出孝常。
4.LEGB作用域
python中的作用域分4種情況:
L:local,局部作用域蚓哩,即函數(shù)中定義的變量构灸;
E:enclosing,嵌套的父級(jí)函數(shù)的局部作用域岸梨,即包含此函數(shù)的上級(jí)函數(shù)的局部作用域喜颁,但不是全局的;
G:globa曹阔,全局變量半开,就是模塊級(jí)別定義的變量;
B:built-in赃份,系統(tǒng)固定模塊里面的變量寂拆,比如int, bytearray等奢米。 搜索變量的優(yōu)先級(jí)順序依次是:作用域局部>外層作用域>當(dāng)前模塊中的全局>python內(nèi)置作用域,也就是LEGB纠永。
local和enclosing是相對(duì)的鬓长,enclosing變量相對(duì)上層來(lái)說(shuō)也是local。
在Python中尝江,只有模塊(module)涉波,類(class)以及函數(shù)(def、lambda)才會(huì)引入新的作用域炭序,其它的代碼塊(如if啤覆、try、for等)不會(huì)引入新的作用域少态。
global關(guān)鍵字
當(dāng)內(nèi)部作用域想修改外部作用域的變量時(shí)城侧,就要用到global和nonlocal關(guān)鍵字了,當(dāng)修改的變量是在全局作用域(global作用域)上的彼妻,就要使用global先聲明一下嫌佑。
nonlocal關(guān)鍵字
global關(guān)鍵字聲明的變量必須在全局作用域上,不能嵌套作用域上侨歉,當(dāng)要修改嵌套作用域(enclosing作用域屋摇,外層非全局作用域)中的變量怎么辦呢,這時(shí)就需要nonlocal關(guān)鍵字幽邓。
小結(jié)
變量查找順序:LEGB炮温,作用域局部>外層作用域>當(dāng)前模塊中的全局>python內(nèi)置作用域;
只有模塊牵舵、類柒啤、及函數(shù)才能引入新作用域;
對(duì)于一個(gè)變量畸颅,內(nèi)部作用域先聲明就會(huì)覆蓋外部變量担巩,不聲明直接使用,就會(huì)使用外部作用域的變量没炒;
內(nèi)部作用域要修改外部作用域變量的值時(shí)涛癌,全局變量要使用global關(guān)鍵字,嵌套作用域變量要使用nonlocal關(guān)鍵字送火。nonlocal是python3新增的關(guān)鍵字拳话,有了這個(gè) 關(guān)鍵字,就能完美的實(shí)現(xiàn)閉包了种吸。
5.特殊函數(shù)
遞歸函數(shù)定義:遞歸函數(shù)就是在函數(shù)內(nèi)部調(diào)用自己
有時(shí)候解決某些問(wèn)題的時(shí)候弃衍,邏輯比較復(fù)雜,這時(shí)候可以考慮使用遞歸骨稿,因?yàn)槭褂眠f歸函數(shù)的話笨鸡,邏輯比較清晰姜钳,可以解決一些比較復(fù)雜的問(wèn)題坦冠。但是遞歸函數(shù)存在一個(gè)問(wèn)題就是假如遞歸調(diào)用自己的次數(shù)比較多的話形耗,將會(huì)使得計(jì)算速度變得很慢,而且在python中默認(rèn)的遞歸調(diào)用深度是1000層辙浑,超過(guò)這個(gè)層數(shù)將會(huì)導(dǎo)致“爆椉さ樱”。判呕。倦踢。所以,在可以不用遞歸的時(shí)候建議盡量不要使用遞歸侠草。
遞歸函數(shù)的優(yōu)點(diǎn):定義簡(jiǎn)單辱挥,邏輯清晰。理論上边涕,所有的遞歸函數(shù)都可以寫(xiě)成循環(huán)的方式晤碘,但循環(huán)的邏輯不如遞歸清晰。
遞歸特性:
1功蜓、必須有一個(gè)明確的結(jié)束條件
2园爷、每次進(jìn)入更深一層遞歸時(shí),問(wèn)題規(guī)模相比上次遞歸都應(yīng)有所減少
3式撼、遞歸效率不高童社,遞歸層次過(guò)多會(huì)導(dǎo)致棧溢出(在計(jì)算機(jī)中,函數(shù)調(diào)用是通過(guò)棧(stack)這種數(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)致棧溢出。)
6.函數(shù)式編程
關(guān)于函數(shù)式編程荤牍,我理解的也不是很深案腺,但是python中有4個(gè)比較重要的內(nèi)置函數(shù),組合起來(lá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是一個(gè)迭代器對(duì)象
對(duì)sequence中的item依次執(zhí)行function(item),將執(zhí)行結(jié)果為True的item做成一個(gè)filter object的迭代器返回晦嵌⊥保可以看作是過(guò)濾函數(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']
對(duì)sequence中的item依次執(zhí)行function(item)旱函,將執(zhí)行結(jié)果組成一個(gè)map object迭代器返回. map也支持多個(gè)sequence响巢,這就要求function也支持相應(yīng)數(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)
對(duì)sequence中的item順序迭代調(diào)用function棒妨,如果有starting_value踪古,還可以作為初始值調(diào)用.
4 、lambda
普通函數(shù)與匿名函數(shù)的對(duì)比:
#普通函數(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 關(guān)鍵字標(biāo)識(shí)伏穆,冒號(hào)(:)左側(cè)表示函數(shù)接收的參數(shù)(a,b) ,冒號(hào)(:)右側(cè)表示函數(shù)的返回值(a+b)。
因?yàn)閘amdba在創(chuàng)建時(shí)不需要命名纷纫,所以枕扫,叫匿名函數(shù)