- 你也能看得懂的Python算法書(shū)
- 王碩 董文馨 張舒行 張潔編著
- 3534字
- 2019-07-25 11:36:20
1.4 函數(shù)
函數(shù)是指用于實(shí)現(xiàn)一個(gè)特定功能并能重復(fù)使用的代碼段。前面學(xué)到的input和print這些函數(shù)是Python語(yǔ)言的內(nèi)建函數(shù),可以直接使用。也可以自己定義函數(shù)來(lái)實(shí)現(xiàn)我們想要的功能,這樣的函數(shù)叫作用戶自定義函數(shù)。本節(jié)就來(lái)了解用戶自定義函數(shù)。
1.4.1 定義子函數(shù)
要想使用函數(shù),必須先定義它。
定義函數(shù)的格式為:
def函數(shù)名(變量名):
其中,變量名指?jìng)鬟M(jìn)子函數(shù)的數(shù)據(jù)在子函數(shù)內(nèi)部對(duì)應(yīng)的變量名,可以沒(méi)有,也可以有一個(gè)或者多個(gè)。函數(shù)名是在調(diào)用函數(shù)時(shí)要使用的名字,兩個(gè)函數(shù)不能有相同的變量名。也就是說(shuō),在Python中已經(jīng)存在print函數(shù),所以在創(chuàng)建自定義函數(shù)時(shí)不能以print作為變量名,但是可以使用Print作為變量名(一個(gè)字符大寫(xiě)了)。
最后,如果這是一個(gè)有返回值的函數(shù),要在函數(shù)的最后寫(xiě)上“return返回值”。
長(zhǎng)篇大論不如一個(gè)例子,這就來(lái)創(chuàng)建一個(gè)函數(shù)看看。
01 def Plus(a,b):
02 print(a+b)
03
04 def Hello():
05 num1=int(input("Hello! Please enter the first number:"))
06 num2=int(input("Please enter the second number:"))
07 return num1,num2
08
09 n1,n2=Hello()
10 Plus(n1,n2)
這是一個(gè)用于計(jì)算兩個(gè)數(shù)的和的程序。第一個(gè)函數(shù)Plus用于計(jì)算兩個(gè)數(shù)的和,第二個(gè)函數(shù)Hello用于向用戶問(wèn)好并輸入兩個(gè)數(shù)字。
Plus函數(shù)被調(diào)用時(shí)(第10行),需要提供兩個(gè)值。a對(duì)應(yīng)n1的值,b對(duì)應(yīng)n2的值,在函數(shù)內(nèi)部使用這兩個(gè)值時(shí)只能調(diào)用a和b,不能調(diào)用n1和n2。如果調(diào)用語(yǔ)句是Plus(3,5),那么a==3、b==5,a和b繼承它們對(duì)應(yīng)位置上的值。這個(gè)函數(shù)沒(méi)有返回值,只需要print,所以在函數(shù)結(jié)尾不需要寫(xiě)return。
從 Hello 函數(shù)的定義語(yǔ)句中可以看到,括號(hào)內(nèi)并沒(méi)有變量名,這代表調(diào)用函數(shù)時(shí)不需要提供任何值。在函數(shù)內(nèi),num1和num2存儲(chǔ)了兩個(gè)輸入的值,用return返回。Python和其他語(yǔ)言不同,可以同時(shí)返回多個(gè)值,而且可以是不同類型的值。返回多個(gè)值時(shí),在等號(hào)的左邊用多個(gè)變量接住,變量之間用逗號(hào)隔開(kāi);同樣,變量繼承它們對(duì)應(yīng)位置上的值。在程序中,n1繼承了num1的值,n2繼承了num2的值。
注意:由于程序是從上到下運(yùn)行(行數(shù)編號(hào)從小到大)的,所以函數(shù)必須在調(diào)用語(yǔ)句的上面定義。也就是說(shuō),程序第9行的代碼如果被換到第3行,程序就會(huì)報(bào)錯(cuò),因?yàn)檫@時(shí)Hello函數(shù)還沒(méi)有被定義。另外,和if、while和for語(yǔ)句相似,函數(shù)的定義語(yǔ)句下的代碼段也要有縮進(jìn)。
在這段程序中,做加法的簡(jiǎn)單任務(wù)不創(chuàng)建函數(shù)其實(shí)更簡(jiǎn)單。在復(fù)雜的程序中,使用自定義函數(shù)可以使解決問(wèn)題的過(guò)程簡(jiǎn)便直觀得多。
主函數(shù)的定義是程序的入口函數(shù)。其他的函數(shù)(不是主函數(shù)的函數(shù)叫作子函數(shù))和方法都在主函數(shù)中調(diào)用。
1.4.2 主函數(shù)
在C語(yǔ)言中,主函數(shù)和子函數(shù)之外的語(yǔ)句只能是定義語(yǔ)句。而在Python中,函數(shù)之外也可以有定義語(yǔ)句之外的語(yǔ)句,比如輸出等。Python程序運(yùn)行時(shí)只會(huì)運(yùn)行不在函數(shù)內(nèi)的代碼和主函數(shù)內(nèi)的代碼段,不會(huì)運(yùn)行子函數(shù)內(nèi)的代碼段。子函數(shù)內(nèi)的代碼段只有在被調(diào)用時(shí)才會(huì)運(yùn)行。
因?yàn)橛羞@個(gè)特性,如果程序的調(diào)用和被調(diào)用范圍僅限于本文件內(nèi),可以不編寫(xiě)主函數(shù),直接在所有子函數(shù)下面編寫(xiě)代碼就可以。但是,為了養(yǎng)成好的習(xí)慣和直觀性,建議在編寫(xiě)程序時(shí)加上主函數(shù)。本書(shū)為了簡(jiǎn)單易懂,有些代碼段不使用主函數(shù)。
下面我們來(lái)了解一下在Python中如何定義主函數(shù)。
01 if __name__=='__main__':
02 print("Inside")
運(yùn)行程序,輸出結(jié)果為:
Inside
if__name__=='__main__'是定義主函數(shù)的語(yǔ)句。定義函數(shù)的時(shí)候要注意代碼塊前面的縮進(jìn)(本質(zhì)上是if語(yǔ)句的格式)。
再來(lái)看一個(gè)例子:
01 def sq(num):
02 print(num*num)
03 print("Outside")
04 if __name__=='__main__':
05 print("Inside")
運(yùn)行程序,輸出結(jié)果為:
Outside
Inside
在函數(shù)外和主函數(shù)內(nèi)的輸出語(yǔ)句都被執(zhí)行了,而子函數(shù)sq因?yàn)闆](méi)有被調(diào)用,其中的輸出語(yǔ)句并沒(méi)有被執(zhí)行。
1.4.3 調(diào)用函數(shù)
在1.4.1節(jié)介紹子函數(shù)時(shí),就在程序中調(diào)用了我們定義的子函數(shù)。但是,不同的子函數(shù)有不同的調(diào)用方法。本節(jié)就來(lái)講解調(diào)用各種函數(shù)的規(guī)律。
在定義子函數(shù)時(shí),還要在函數(shù)的括號(hào)中定義好需要傳進(jìn)子函數(shù)的變量。調(diào)用函數(shù)的格式和為函數(shù)定義的需要傳進(jìn)函數(shù)的變量有關(guān)。調(diào)用函數(shù)時(shí)傳進(jìn)的數(shù)據(jù)是什么類型的變量,函數(shù)內(nèi)部對(duì)應(yīng)位置上的變量就會(huì)是同樣類型的。
比如,我們定義了一個(gè)函數(shù) calc,需要三個(gè)變量,最后返回的值是第一個(gè)變量和第二個(gè)變量的乘積減去第三個(gè)數(shù)的值,如圖1.29所示。

圖1.29 函數(shù)calc
函數(shù)定義和調(diào)用時(shí)的格式是這樣的:
01 def calc(a,b,c):
02 ans=a*b-c
03 return ans
04 ans=calc(2,3,4)
05 print(ans)
運(yùn)行程序,輸出結(jié)果:
2
如果在調(diào)用函數(shù)時(shí)寫(xiě)的是calc('2',3,4),那么函數(shù)就會(huì)在執(zhí)行的時(shí)候出錯(cuò),因?yàn)椋?'對(duì)應(yīng)的是a,3對(duì)應(yīng)的是b,4對(duì)應(yīng)的是c,string類型的變量無(wú)法和int類型的變量進(jìn)行計(jì)算。
值得注意的是,在調(diào)用函數(shù)時(shí),我們還使用了一個(gè)變量來(lái)存儲(chǔ)函數(shù)的返回值。需不需要這個(gè)變量取決于函數(shù)的內(nèi)容。如果函數(shù)有返回值,也就是有 return 語(yǔ)句的話,就需要用一個(gè)變量存儲(chǔ)這個(gè)返回值;反之,如果沒(méi)有返回值,那么就可以直接調(diào)用,不需要變量來(lái)存儲(chǔ)返回值。
如果想要輸出這個(gè)返回的值,或者再使用它進(jìn)行其他一次性操作,也可以不專門用一個(gè)變量存儲(chǔ),而直接把這個(gè)函數(shù)寫(xiě)入進(jìn)行操作的語(yǔ)句中。再拿calc函數(shù)舉例說(shuō)明:
01 def calc(a,b,c):
02 ans=a*b-c
03 return ans
04 print(calc(2,3,4))
運(yùn)行程序,輸出結(jié)果為:
2
這樣,就達(dá)到了簡(jiǎn)化程序的目的。
再來(lái)舉一個(gè)沒(méi)有返回值的函數(shù)的例子:
01 def Output(strArr):
02 for i in range(10):
03 print(strArr[i])
04 Arr=['Apple','Bear','Cat','Dog','Egg','Fruit','Giraffe','Hat','Ice','Jacket']
05 Output(Arr)
運(yùn)行程序,輸出結(jié)果為:
Apple
Bear
Cat
Dog
Egg
Fruit
Giraffe
Hat
Ice
Jacket
1.4.4 全局變量
在之前見(jiàn)到的程序中,子函數(shù)內(nèi)部的變量和子函數(shù)外部的變量完全不相關(guān),所以不必?fù)?dān)心重名的問(wèn)題;子函數(shù)外的語(yǔ)句無(wú)法調(diào)用子函數(shù)內(nèi)部的變量,子函數(shù)內(nèi)部的語(yǔ)句也無(wú)法調(diào)用子函數(shù)外部的變量。這使程序的結(jié)構(gòu)更加清晰,但也帶來(lái)了一些不便:難道想使用外部的數(shù)據(jù)就必須要傳入子函數(shù)中嗎?
全局變量,顧名思義,就是可以讓整個(gè)程序使用的變量。它一般在整個(gè)程序的最開(kāi)始定義,在所有的函數(shù)和語(yǔ)句的上方。如圖1.30所示,局部變量只在函數(shù)的小范圍內(nèi)存在,跳出這個(gè)范圍,局部變量不存在。而全局變量在整個(gè)程序的范圍內(nèi)存在。

圖1.30 全局變量與局部變量
再次用calc函數(shù)舉例說(shuō)明:
01 g=10
02 def calc(a,b,c):
03 ans=a*b-c
04 return ans
05 print(calc(2,3,4))
在這段程序中,g 就是一個(gè)全局變量。在主函數(shù)和自己定義的子函數(shù)之外的所有語(yǔ)句中,都可以像調(diào)用一個(gè)平常變量一般調(diào)用它。但是,在子函數(shù)內(nèi)部時(shí),就要給它多加一條語(yǔ)句:
01 global g
global 的意思是“全球的”,在程序中也可以被理解為“全局的”。在子函數(shù)內(nèi),在變量名前面加上global這條語(yǔ)句用于聲明這是一個(gè)全局變量。有了這條語(yǔ)句,這個(gè)子函數(shù)內(nèi)的所有代碼都可以像各個(gè)子函數(shù)外的代碼一樣調(diào)用這個(gè)變量并對(duì)它進(jìn)行更改,而且更改的結(jié)果也會(huì)在全局范圍內(nèi)保存。與調(diào)用函數(shù)時(shí)傳進(jìn)函數(shù)的變量不同,在函數(shù)內(nèi)更改這些非全局變量并不會(huì)影響它們本來(lái)的值。
1.4.5 函數(shù)的運(yùn)用
我們來(lái)看一個(gè)問(wèn)題:1個(gè)蘋(píng)果2元,1個(gè)菠蘿8元,1個(gè)西瓜10元。1個(gè)盒子1元,它最多能裝下5個(gè)蘋(píng)果或1個(gè)菠蘿或1個(gè)西瓜。編寫(xiě)一個(gè)程序,讓用戶輸入每種水果的購(gòu)買數(shù)量,然后輸出每種水果加上盒子需要多少錢,以及一共要多少錢。
先自己思考一下該怎么做,再來(lái)看下面的代碼。
首先是沒(méi)有使用函數(shù)的解決方法:

然后是使用了函數(shù)的解決方法:


現(xiàn)在,你熟悉子函數(shù)的定義和使用方法了嗎?
根據(jù)圖1.31所示的關(guān)系來(lái)寫(xiě)一個(gè)滿足問(wèn)題要求的程序。

圖1.31 各科分?jǐn)?shù)評(píng)價(jià)
首先,允許用戶輸入數(shù)學(xué)、英語(yǔ)、歷史這三科的考試分?jǐn)?shù),每一科的分?jǐn)?shù)范圍在0~100之間,超出這個(gè)范圍的分?jǐn)?shù)是錯(cuò)誤分?jǐn)?shù),需要重新輸入。第二,對(duì)每一科的分?jǐn)?shù)做出評(píng)價(jià),評(píng)價(jià)標(biāo)準(zhǔn)如圖1.31所示。
第三,按表1.2中規(guī)定的比例折算各科分?jǐn)?shù)并得到總分,總分范圍是0~300。
表1.2 各科折算總分的比例

續(xù)表

第四,按照表1.3中的標(biāo)準(zhǔn),給總分一個(gè)等級(jí)。最后,輸出對(duì)每一門課考試成績(jī)的評(píng)價(jià)、折算完的總分?jǐn)?shù)和總分對(duì)應(yīng)的等級(jí)。分別用5個(gè)子函數(shù)實(shí)現(xiàn)這5個(gè)要求。
表1.3 總分對(duì)應(yīng)等級(jí)

這是一個(gè)比較復(fù)雜的題目,提供的數(shù)據(jù)和條件比較多。先自己思考該怎么做,用紙和筆記錄下自己的思路和計(jì)劃,再動(dòng)手去寫(xiě)代碼。寫(xiě)完代碼后,再對(duì)照書(shū)上的答案驗(yàn)證。記住,不同的代碼也可以實(shí)現(xiàn)相似的功能,書(shū)上的答案僅供參考。
那么,首先來(lái)寫(xiě)出這個(gè)程序的框架:

先定義好所有要使用的子函數(shù)和主函數(shù)。語(yǔ)句next是用來(lái)“跳過(guò)”一個(gè)子函數(shù)的。當(dāng)子函數(shù)內(nèi)部沒(méi)有任何語(yǔ)句時(shí),Python就會(huì)把下一個(gè)子函數(shù)或者主函數(shù)當(dāng)作子函數(shù)內(nèi)部的語(yǔ)句,從而因?yàn)榭s進(jìn)不對(duì)而報(bào)錯(cuò),加上next語(yǔ)句就可以有效地防止這種情況的發(fā)生。同時(shí),根據(jù)子函數(shù)的功能來(lái)判斷它們需要什么值來(lái)完成任務(wù),從而確定括號(hào)內(nèi)的變量。
現(xiàn)在,就把這些子函數(shù)填滿。


到這里,整個(gè)程序就完成了。
看完這兩個(gè)問(wèn)題之后可以發(fā)現(xiàn),如果沒(méi)有注釋的話,沒(méi)有使用函數(shù)的解決方法雖然也不難完成,但是在寫(xiě)完一大段連著的代碼之后很容易混淆代碼的用處。而使用了函數(shù)就可以有效避免這種情況的發(fā)生。所以,使用函數(shù)還可以讓程序變得更有條理。
到這里,第1章就結(jié)束了。在接下來(lái)要學(xué)習(xí)的諸多算法中,將會(huì)大量使用本章講解的語(yǔ)法。在進(jìn)入下一章之前,一定要先熟悉這些語(yǔ)法,可以多做題目來(lái)練習(xí)。如果你覺(jué)得還沒(méi)有弄懂,那就請(qǐng)重新讀一讀本章再繼續(xù)接下來(lái)的學(xué)習(xí)吧!
- Vue.js 3.x快速入門
- Learning LibGDX Game Development(Second Edition)
- Visual FoxPro程序設(shè)計(jì)教程
- 造個(gè)小程序:與微信一起干件正經(jīng)事兒
- Flash CS6中文版應(yīng)用教程(第三版)
- 名師講壇:Spring實(shí)戰(zhàn)開(kāi)發(fā)(Redis+SpringDataJPA+SpringMVC+SpringSecurity)
- Java實(shí)戰(zhàn)(第2版)
- Python網(wǎng)絡(luò)爬蟲(chóng)技術(shù)與應(yīng)用
- Mastering SciPy
- 大規(guī)模語(yǔ)言模型開(kāi)發(fā)基礎(chǔ)與實(shí)踐
- Keil Cx51 V7.0單片機(jī)高級(jí)語(yǔ)言編程與μVision2應(yīng)用實(shí)踐
- Mastering OpenStack
- Web前端測(cè)試與集成:Jasmine/Selenium/Protractor/Jenkins的最佳實(shí)踐
- C#網(wǎng)絡(luò)編程高級(jí)篇之網(wǎng)頁(yè)游戲輔助程序設(shè)計(jì)
- JSP編程教程