目錄:
函數(shù)式編程
傳參與返回值
遞歸
匿名函數(shù)
閉包
高階函數(shù)
內(nèi)置函數(shù)
在第三章,我們引入新的概念函數(shù),在以往的代碼編寫中我們都是用的過程式編程,函數(shù)式編程的特點(diǎn)將過程式編程變成易于管理調(diào)用的小模塊,
讓重復(fù)的代碼可以反復(fù)的調(diào)用,大大減少代碼量,懶惰即美德
一、函數(shù)式編程
創(chuàng)建函數(shù)
一個函數(shù)式由關(guān)鍵字 def ,與函數(shù)名與括號冒號,和括號中的參數(shù)組成,當(dāng)想要執(zhí)行函數(shù)的時候只需要寫上函數(shù)名加括號即可
格式: def function (parameter) 下面就創(chuàng)建一個函數(shù)
第一個函數(shù)
變量的作用域
我們看一個例子,在下面代碼中我們先把變量 a=“haha” 然后在函數(shù)中把 a=“heihei” 最后執(zhí)行這個函數(shù),并輸出變量a的結(jié)果
我們發(fā)現(xiàn)為什么a不等于 "heihei",而是我們之前賦值的 “haha” 這個現(xiàn)象我們馬上揭秘
變量的作用域例一
全局變量與局部變量
很明顯變量的作用域就是變量在哪一個范圍內(nèi)生效,如果出了這個范圍則無法使用
全局變量:通常全局變量存活在腳本運(yùn)行結(jié)束,并且所有的函數(shù)都可以訪問它
局部變量:只能局部變量所在的函數(shù)內(nèi)部調(diào)用,并且除非把局部變量聲明成全局變量否則,其他函數(shù)均無法調(diào)用,并且局部變量
當(dāng)所在的函數(shù)執(zhí)行完成后就不存在了
全局變量與局部變量
global
global就是可以把局部變量變成全局變量的,如果被聲明的局部變量名與全局變量名一樣的話,那么局部變量會覆蓋全局變量,切
使用global聲明變量需要在變量之前聲明否則python會告訴你,你需要在 a 前面聲明
報錯提示:SyntaxWarning: name 'a' is assigned to before global declaration global a
gloable
二、傳參與返回值
傳參
函數(shù)用起來比較簡單也容易理解,但是參數(shù)的變化就比較多了,在函數(shù)括號內(nèi)就是參數(shù),參數(shù)可以接收字符串,數(shù)字,也可以接收字典和列表
并且在調(diào)用的時候,我們還可以指定給哪個參數(shù)賦什么值
傳參
當(dāng)我們想要傳入列表或者字典時需要怎么辦?
傳入字典或列表
默認(rèn)參數(shù)
在函數(shù)中還可以設(shè)置默認(rèn)參數(shù),默認(rèn)參數(shù)的意思是這個參數(shù)你可以傳值也可以不傳值,當(dāng)不傳值的時候這個參數(shù)就等于默認(rèn)值
默認(rèn)參數(shù)
非固定參數(shù)
非固定參數(shù)的意義在于可以接收任意個值,在你的函數(shù)不確定用戶想傳入多少個值的時候使用,當(dāng)然在調(diào)用有只有非固定參數(shù)的函數(shù)的時候我們可以不傳參數(shù)。
非固定參數(shù)分一個*和兩個*,*args會把傳入的參數(shù)變成元祖,**kwargs把傳入的參數(shù)變成字典,當(dāng)然*ages可以是別的名稱,但是在規(guī)范中最好使用*args,和**kwargs
非固定傳參
既然形參可以帶*和**,那么實參也是可以帶*和**,那么*就是配合列表使用的,**就是配合字典的!
解參
實參帶*就會把列表分解成 "Ben","22","Man" 一個一個單獨(dú)的元素傳入函數(shù),而**會把字典分解成name="Ben",age="022",aender="Man"
這種鍵值對傳入函數(shù)。
形參與實參
形參:
變量只有在被調(diào)用時才分配內(nèi)存單元,在調(diào)用結(jié)束時,即刻釋放所分配的內(nèi)存單元。因此,形參只在函數(shù)內(nèi)部有效。函數(shù)調(diào)用結(jié)束返回主調(diào)用
函數(shù)后則不能再使用該形參變量
實參:
可以是常量、變量、表達(dá)式、函數(shù)等,無論實參是何種類型的量,在進(jìn)行函數(shù)調(diào)用時,它們都必須有確定的值,以便把這些值傳送給形參。因此
應(yīng)預(yù)先用賦值,輸入等辦法使參數(shù)獲得確定值
注!當(dāng)普通參數(shù)和默認(rèn)參數(shù)和非固定參數(shù)結(jié)合使用的時候,要遵循一個順序,普通參數(shù)在默認(rèn)參數(shù)前面,默認(rèn)參數(shù)在非固定參數(shù)前面
返回值
在正常使用函數(shù)的時候,函數(shù)是可以把函數(shù)內(nèi)部處理的結(jié)果返回給函數(shù)調(diào)用者的,在沒有返回值得函數(shù)中會保留None傳給函數(shù)調(diào)用者,返回值可以返回序列等
在函數(shù)執(zhí)行的時候遇到return函數(shù)會停止執(zhí)行,并返回結(jié)果
return
嵌套函數(shù)
在函數(shù)內(nèi)部也可以寫函數(shù),這樣就是外層函數(shù)套著內(nèi)側(cè)函數(shù),這種形式稱之為嵌套函數(shù),同理因為作用域的關(guān)系嵌套函數(shù)只能內(nèi)部調(diào)用
return unction_2(stra)+"我是第二層\n" 就等于先 c = unction_2(stra) 然后 return c+"我是第二層\n"
嵌套函數(shù)
三、遞歸
前面已經(jīng)介紹了函數(shù)相關(guān)的知識,在函數(shù)中,函數(shù)可以調(diào)用其他的函數(shù),并且函數(shù)還可以調(diào)用自身,利用這種特性我們可以完成一些特定的
操作,這種函數(shù)調(diào)用自身的形式就是遞歸
def recursion() :
return recursion()
在遞歸中不能像上面兩行一樣一直調(diào)用自身,這樣一會程序就會崩潰,因為它永遠(yuǎn)的在調(diào)用就跟while死循環(huán)一樣出不去,所以遞歸也需要進(jìn)
判斷給它出口
例子:階乘
什么是階乘,階乘就是給一個自然數(shù)N,然后計算N的階乘那么 N = 1x2x3x4....N ,這個就是階乘,我們可以把它到過來看,
N = N x (n-1) x (n-2) x (n-3) ...... 1 一直乘到括號中的值等于1,既然知道了階乘是什么,那么我們來寫一個程序?qū)崿F(xiàn)它
階乘非遞歸版本
剖析:上面的例子首先把n=4傳入進(jìn)去,然后通過 for i in range(1,4)讓i分別等于1,2,3,然后進(jìn)行 n*=i,我們可以看出這個for循環(huán)是循環(huán)3次的
第一次(n = n*i) n = 4*1 ,此時n還是等于4
第二次(n = 4*i) n = 4*2 此時n = 8
第三次(n = 8*i) n = 8*3 此時n等于24
此時for循環(huán)了3次所以結(jié)束了,通過return把n的結(jié)果返回,所以最終結(jié)果算出 4的階乘等于24
遞歸版本
下面看遞歸版本的階乘
階乘遞歸版本
剖析:
首先c = factorial(4)開始執(zhí)行函數(shù),然后進(jìn)行第一次判斷 n == 1,顯然第一層n不等于1,然后碰到return n * factorial(n-1),碰到return本來是要返回的,但是 factorial(n-1)
有調(diào)用了factiorial這個函數(shù),因此進(jìn)入了第二層
第二層因為上一層傳入的參數(shù)是n-1,所以第二層的n是等于3的,然后判斷,這一層的n也不等于1,然后又進(jìn)入第三層
第三層n等于3,然后判斷這一層的n還不等于1,然后又進(jìn)入第四層
到第四層的時候這時的 n就等于1,所以觸發(fā)了 return 1 不再調(diào)用函數(shù)了,所以就開始返回
返回第三層 return n * factorial(n-1) , 此時factorial(n-1) 就等于第四層return上去的1,所以第三層返回時就等于return n * 1(return 2 * 1),并且第三層n是等于2的
返回第二層factorial(n-1)就等于第三層return上去的2,并且第二層n是等于3的,return 3 * 2
返回第一層factorial(n-1)就等于第二層return上去的6,并且第一層n是等于4的,return 4 * 6
到此為止遞歸執(zhí)行完畢,c就等于 4 * 6 c=24
四、匿名函數(shù)
匿名函數(shù)也叫l(wèi)ambda函數(shù),函數(shù)沒有具體的名稱。語法:function name= lambda args(多個參數(shù)用逗號隔開): Expression(表達(dá)式,表達(dá)式的結(jié)果就是返回值)
先來看一個最簡單例子:
匿名函數(shù)
有認(rèn)識,這個匿名函數(shù)和普通函數(shù)沒有什么區(qū)別么,其實匿名函數(shù)就像三元運(yùn)算一樣,并且能夠用lambda函數(shù)有幾大優(yōu)勢
1、在一些不會再別的地方調(diào)用的函數(shù),我們可以使用匿名函數(shù),并且這樣簡化了代碼,看起來更加整潔。
2、lambda函數(shù)將會搭配一些內(nèi)置函數(shù)來使用(下面會涉及到)
五、閉包
在上面的示例中知道了函數(shù)可以調(diào)用函數(shù)本身,這種形式稱之為遞歸,那么還可以將函數(shù)作為參數(shù)返回,這種形式就稱之為閉包
閉包最大的好處就是即用即調(diào),閉包對于安裝計算,隱藏狀態(tài),以及在函數(shù)對象和作用域中隨意地切換是很有用的!
閉包示例
例子中做了一個減去手續(xù)費(fèi)后返回余額的功能,首先執(zhí)行了func函數(shù),將利率封裝了進(jìn)去,然后,func函數(shù)把它內(nèi)部的函數(shù)進(jìn)行了進(jìn)行了返回
要知道當(dāng)函數(shù)不加括號的時候是不執(zhí)行的!,所以此時closoure就是 add_func 函數(shù)的內(nèi)存地址,當(dāng)想要使用這個功能的時候,直接把closoure加括號
并傳入值即可執(zhí)行。并且可以看到的是在全局作用域中執(zhí)行,隨時可以切換到局部作用域。
六、高階函數(shù)
函數(shù)可以用來當(dāng)做返回值,可以用調(diào)用自己本身,高階函數(shù)就是函數(shù)的參數(shù)把另一個函數(shù)作為參數(shù),這種函數(shù)就稱之為高階函數(shù)。
高階函數(shù)
編寫高階函數(shù),就是讓函數(shù)的參數(shù)能夠接收別的函數(shù)。
七、內(nèi)置函數(shù)
內(nèi)置函數(shù)就是python中內(nèi)置的一些方法,內(nèi)置函數(shù)官方介紹請猛戳這里
內(nèi)置函數(shù)使用方法示例,詳細(xì)介紹請參考
內(nèi)置方法