函數(shù)
函數(shù)是可以重復(fù)使用的程序片段赞草,函數(shù)讓你命名一塊語句代碼,允許你使用這個(gè)具體的函數(shù)名祭刚,在程序的任何地方,任何次數(shù)的運(yùn)行那段代碼墙牌。這被稱作調(diào)用函數(shù)涡驮。我們已經(jīng)多次使用過像 len 和 range這樣的內(nèi)置函數(shù)了。
函數(shù)概念可能是任一重要軟件的最重要的基礎(chǔ)材料(在任何一門編程語言)憔古,所以我們將在這一節(jié)探討函數(shù)的各個(gè)方面遮怜。
函數(shù)用def 關(guān)鍵字定義淋袖,def關(guān)鍵字后面跟著函數(shù)的標(biāo)識符名字(函數(shù)名)鸿市,然后是一對括號,括號內(nèi)可以包含一些變量即碗,然后是冒號結(jié)束這一行焰情。下一行就是代碼塊的開始,是函數(shù)的一部分剥懒。下面的例子顯示内舟,實(shí)際上挺簡單的。
Def sayHello():
print(‘hello world’)
然后調(diào)用
sayHello()
sayHello()
調(diào)用多少次都行初橘。
代碼運(yùn)行原理
我們定義了一個(gè)函數(shù)叫做sayHello,使用上面解釋的語法验游。這個(gè)函數(shù)沒有parameters (一般翻譯成形式參數(shù)),所以沒有在括號內(nèi)聲明變量保檐。Parameters 對于函數(shù)耕蝉,就像是函數(shù)的一個(gè)輸入。所以夜只,可以直接傳遞給函數(shù)各種不同的值垒在。然后得到(函數(shù)返回)的相應(yīng)的值。
看到了嗎扔亥?我們可以兩次調(diào)用同樣的函數(shù)场躯,這意味著沒有必要寫兩次同樣的代碼。
函數(shù)形式參數(shù)(parameters)
一個(gè)函數(shù)可以接收參數(shù)旅挤,也就是我們提供給函數(shù)的值踢关,函數(shù)用這些值做些事情。這些參數(shù)就像變量粘茄,除非這些變量的值在我們調(diào)用(就是使用函數(shù))函數(shù)時(shí)耘成,已經(jīng)被定義。并且在函數(shù)運(yùn)行時(shí)已經(jīng)被賦值。
在定義函數(shù)時(shí)括號內(nèi)被指定的參數(shù)瘪菌,用逗號隔開撒会,(叫做parameters,中文翻譯為形式參數(shù))师妙,當(dāng)我們調(diào)用函數(shù)時(shí)诵肛,我們以同樣方式提供值。請注意默穴,這個(gè)術(shù)語怔檩,函數(shù)定義時(shí)的參數(shù)名字叫做形式參數(shù),而我們提供給函數(shù)參數(shù)值時(shí)蓄诽,參數(shù)叫做實(shí)際參數(shù)(auguments)薛训。(譯者又及—英文容易區(qū)別和理解,因?yàn)閱卧~十分不同仑氛,但中文容易混淆乙埃,請留意。要理解區(qū)分這兩個(gè)術(shù)語锯岖,因?yàn)楹竺鏁?huì)頻繁使用介袜。不能像某些視頻上那樣說的,這種區(qū)分無所謂出吹。因?yàn)槔砬逅悸沸枰@些術(shù)語遇伞。有英語基礎(chǔ)的直接記憶英文詞最佳)
例子:
Def printMax (a, b):
If a > b:
Print (a, ‘ is maximum’)
elif a == b:
print (a, ‘ is equal to’, b)
else:
print (b, ‘ is maximum’)
下面直接傳值
printMax(3,5)
下面?zhèn)鬟f變量作為實(shí)際參數(shù)
x= 5
y= 7
printMax ( x, y)
代碼運(yùn)行原理
我們定義了一個(gè)函數(shù)叫做 printMax 用了兩個(gè)形式參數(shù),分別是 a 和 b捶牢; 我們用一個(gè)簡單的 if … else 語句鸠珠, 發(fā)現(xiàn)更大的數(shù)字,然后打印出較大的那個(gè)數(shù)字秋麸。
第一次調(diào)用函數(shù)時(shí)渐排,我們直接提供數(shù)字作為實(shí)際參數(shù)(以后簡稱實(shí)參,形式參數(shù)簡稱形參)竹勉,第二個(gè)例子飞盆,我們用變量作為實(shí)際參數(shù)調(diào)用函數(shù)。這樣的話次乓,就是將實(shí)際參數(shù)(x)的值賦值給了(綁定)形式參數(shù)a 吓歇。而實(shí)際參數(shù)(y)的值賦值(綁定)給了形式參數(shù)b。printMax函數(shù)在兩個(gè)例子中運(yùn)作方式是一樣的票腰。
局部變量
當(dāng)你定義函數(shù)時(shí)城看,在其內(nèi)部聲明變量的時(shí)候,它們與函數(shù)外部使用的同名變量沒有一毛錢關(guān)系杏慰。也就是說测柠,對函數(shù)來說炼鞠,變量名字就是local的,這就叫做變量的scope(作用域)轰胁。從變量定義名字的點(diǎn)開始谒主,變量的作用域就開始了,一直到它聲明變量所在的那塊語句塊結(jié)束而結(jié)束赃阀。不好理解的話霎肯,看例子:
X = 50
Def func(x):
print(‘x is’, x)
x = 2
print(‘changed local x to’, x)
func(x)
print(‘x is still’, x)
代碼運(yùn)行原理
在函數(shù)體內(nèi)部第一行,我們第一次打印名字為x 的值榛斯,Python使用的是在主體語句塊(函數(shù)定義的上面)聲明形式參數(shù)的值观游。接下來,我們將2賦值給x 驮俗,x 是局部變量懂缕,當(dāng)我們變動(dòng)函數(shù)體內(nèi)部的x時(shí), 在函數(shù)外面的主體代碼里的x值是不受影響的。
最后的這個(gè)print語句王凑,展示了x在主體語句塊中的值搪柑,所以,前面調(diào)用的這個(gè)函數(shù)荤崇,證實(shí)了它(外面的x)實(shí)際上是不受函數(shù)內(nèi)部的局部變量賦值所影響的拌屏。
全局變量語句
如果你要把一個(gè)值賦值給一個(gè)程序中最頂端的一個(gè)名字潮针,(比如术荤,沒有在任何像函數(shù)和類內(nèi)部的作用域中),你需要告訴Python每篷,名稱是不是局部的瓣戚,是全局的。 我們使用 global 語句做這事焦读。不可能在函數(shù)外部子库,不使用global 語句來定義一個(gè)變量(譯者表示懷疑,還是能不使用global就不使用它吧矗晃。)
(還有一段沒有翻譯仑嗅,譯者感覺翻譯了就有點(diǎn)亂了)
其實(shí)是在函數(shù)內(nèi)用global,來定義全局變量张症。(譯者澄清)例子:
非常遺憾仓技,圖片無法上傳,請移步到CSDN博客(Mark學(xué)編程)或者微信公眾號(Mark學(xué)編程)或者QQ加群(Mark學(xué)編程)參考俗他。沒有辦法脖捻,只能這樣給人一廣告之嫌了。
作者說了好多global兆衅,感覺作者有點(diǎn)混地沮。不過嗜浮,你要簡化的話,把這個(gè)例子看懂了摩疑,就行了危融。例子中,函數(shù)內(nèi)用global聲明了x全局變量雷袋。所以专挪,當(dāng)在函數(shù)內(nèi)部重新賦值給x時(shí),這個(gè)變化就已經(jīng)影響到了函數(shù)外部主體塊中x的值片排。(據(jù)說寨腔,大牛們對global的使用有著較大的分歧,所以率寡,能避免就避免吧迫卢。畢竟我們不是大牛—譯者注)
默認(rèn)實(shí)參值
有些函數(shù)冶共,你可能需要讓一些形式參數(shù)成為可選乾蛤,此時(shí)這些可選的參數(shù)要使用默認(rèn)值赞别,以防止用戶不提供這些參數(shù)值力喷。我們使用默認(rèn)實(shí)參值搞定此事。(也就是)在函數(shù)定義時(shí)匣距,用賦值運(yùn)算符(=)后面緊跟著默認(rèn)值庙楚,附在形式參數(shù)名后面上荡,從而將默認(rèn)實(shí)際參數(shù)值指定給了形式參數(shù)。
請注意馒闷,默認(rèn)實(shí)際參數(shù)值應(yīng)該是常數(shù)酪捡,更準(zhǔn)確的說,默認(rèn)實(shí)參值應(yīng)當(dāng)是不可變的纳账,這會(huì)在今后章節(jié)中詳細(xì)講解」滢保現(xiàn)在,只要記住就好疏虫。
例子:
Def say(message, times=1):
Print(message * times)
say(‘hello’)
say(‘world’, 5)
代碼運(yùn)行原理
叫say名字的函數(shù)用于打印字符串永罚,根據(jù)指定次數(shù)決定打印次數(shù)。如果我們不提供值卧秘,那么呢袱,依據(jù)默認(rèn),字符串只打印一次斯议。我們通過指定一個(gè)默認(rèn)實(shí)參值 1 給形式參數(shù) times 來達(dá)成這個(gè)目的产捞。
在say 的第一次調(diào)用時(shí),我們僅僅提供了字符串哼御,所以它只打印了字符串一次坯临。在第二次調(diào)用時(shí)焊唬,我們提供了兩者–字符串和實(shí)際參數(shù)5,指出我們要“say”這個(gè)字符串信息5遍看靠。
小心:
只有在形式參數(shù)列表的結(jié)尾部分赶促,形式參數(shù)才能給予默認(rèn)實(shí)際參數(shù)值。你不能在一個(gè)沒有默認(rèn)值的形參前面挟炬,放置一個(gè)有默認(rèn)值的形參鸥滨。這是因?yàn)橹蒂x值給形參是依據(jù)位置的。例如: def func(a, b=5) 是有效的谤祖,但是 def func(a=5, b) 是無效的婿滓。
關(guān)鍵字實(shí)參
如果你有些函數(shù)有許多形式參數(shù),你需要特別指定一些參數(shù)粥喜,那么你可以給予形式參數(shù)賦值并命名形式參數(shù)凸主,這叫做關(guān)鍵字實(shí)參。我們使用名字(關(guān)鍵字)而不是用位置(我們一直這么做)來具體的指定函數(shù)的實(shí)際參數(shù)额湘。
這樣做有兩個(gè)好處卿吐,其一,使用函數(shù)更容易锋华,因?yàn)槲覀儫o需擔(dān)憂實(shí)際參數(shù)的次序嗡官。其二,我們只賦值我們想要賦值的形參的毯焕,假設(shè)其他形參有實(shí)參默認(rèn)的值衍腥。
舉例:
def func(a, b=5, c=10):
print(‘a(chǎn) is’, a, ‘a(chǎn)nd b is’, b, ‘a(chǎn)nd c is’, c)
func(3, 7)
func(25, c=24)
func(c=50, a=100)
輸出:
a is 3 and b is 7 and c is 10
a is 25 and b is 5 and
c is 24 a is 100 and b is 5 and c is 50
代碼運(yùn)行原理
叫做func的函數(shù)有一個(gè)形式參數(shù),其沒有默認(rèn)參數(shù)值芥丧,后面的兩個(gè)形式參數(shù)有默認(rèn)值紧阔。
第一個(gè)用法坊罢,func(3,7), 形式參數(shù)a 得到3這個(gè)值续担,b 是 7;c 得到默認(rèn)值10活孩;
第二個(gè)用法物遇,func(25, c=24), a 得到25的值,因?yàn)槲恢煤度澹琧是24询兴,因?yàn)槭顷P(guān)鍵字實(shí)參,變量 b 得到默認(rèn)的值5起趾;
第三個(gè)用法诗舰,func(c=50, a=100), 我們使用關(guān)鍵字實(shí)參為所有指定參數(shù)賦值。請注意训裆,次序已經(jīng)無足輕重眶根。
(不知道你掌握了嗎蜀铲?,在調(diào)用函數(shù)時(shí)属百,參數(shù)列出的使用列出的實(shí)參记劝,沒有的使用默認(rèn)實(shí)參值。明確列出有關(guān)鍵字的用關(guān)鍵字實(shí)參族扰,沒有關(guān)鍵字的按照位置實(shí)參—應(yīng)該是這么理解比較全面吧—譯者加注厌丑,anyway, 需要大量練習(xí)才行)
VarArgs 形參
有時(shí)候,我們定義的函數(shù)需要使用不定數(shù)量的形參渔呵,也就是說怒竿,實(shí)參的數(shù)量是變化的,可以使用星號達(dá)成這個(gè)目的扩氢。
例子:
非常遺憾愧口,圖片無法上傳,請移步到CSDN博客(Mark學(xué)編程)或者微信公眾號(Mark學(xué)編程)或者QQ加群(Mark學(xué)編程)參考类茂。沒有辦法耍属,只能這樣給人一廣告之嫌了。
代碼運(yùn)行原理
當(dāng)我們聲明一個(gè)帶星號的形式參數(shù)巩检,比如 param厚骗, 然后所有的位置實(shí)參,從這一點(diǎn)開始一直到結(jié)束兢哭,都被收集到一個(gè)叫做param的元組中领舰。
同樣的,當(dāng)我們聲明一個(gè)帶雙星號的形參時(shí)迟螺,比如param冲秽,我們把從這一點(diǎn)開始到結(jié)尾的關(guān)鍵字參數(shù)收集起來,作為一個(gè)字典稱作*param矩父。
我們會(huì)在今后章節(jié)探討元組和字典
return語句
此語句用于函數(shù)返回锉桑。比如打斷函數(shù),我們也可以選擇性使用return從函數(shù)返回一個(gè)值窍株。
例子:
Def maximum(x, y):
If x > y:
return x
elif x == y:
return (‘the number are equal’)
else:
return y
print(maximum(2,5))
代碼運(yùn)行原理
此函數(shù)返回形參中最大的民轴,在這個(gè)例子中,就是我們提供給函數(shù)的數(shù)字球订。它使用了一個(gè)簡單的if…else語句發(fā)現(xiàn)更大的值然后返回那個(gè)值后裸。
請注意,一個(gè)return語句沒有值的話相當(dāng)于return None. None 是Python的一個(gè)特別類型冒滩,代表空微驶。比如,如果你有個(gè)None值开睡,那就被用于表示那個(gè)變量沒有值因苹。
每個(gè)函數(shù)都暗含一個(gè)return None 語句较店,除非你已經(jīng)寫了自己的return語句。你可以通過運(yùn)行print(someFunction())來體會(huì)這一點(diǎn)(你可以print(someFunction())容燕。此函數(shù)沒有使用return語句梁呈,如下:
def someFunction():
pass
Python中的pass語句用于表示空語句塊。
文檔字符串
Python有一個(gè)極好的特征叫做文檔字符串蘸秘。通常用它的更短的名字來引用(DocStrings)官卡,這是個(gè)重要的工具供你使用。這將幫助你寫出更好的程序的文檔醋虏,使程序更容易理解寻咒。令人驚奇的是,我們甚至可以在程序?qū)嶋H運(yùn)行時(shí)颈嚼,得到文檔毛秘,比如說從一個(gè)函數(shù)里。見圖例子:
非常遺憾阻课,圖片無法上傳叫挟,請移步到CSDN博客(Mark學(xué)編程)或者微信公眾號(Mark學(xué)編程)或者QQ加群(Mark學(xué)編程)參考。沒有辦法限煞,只能這樣給人一廣告之嫌了抹恳。
代碼運(yùn)行原理:
函數(shù)第一邏輯行的字符串是這個(gè)函數(shù)的文檔字符串。請注意署驻,文檔字符串同樣應(yīng)用于模塊(modules)和 類(classes)奋献,這些我們將在相應(yīng)章節(jié)學(xué)習(xí)。
習(xí)慣上旺上,文檔字符串是個(gè)多行的字符串瓶蚂,第一行開始一個(gè)大寫字母,然后結(jié)束用英語句號宣吱。然后第二行空行窃这,然后第三行開始詳細(xì)的解釋(遺憾的是,我上面的圖沒有遵守凌节,不換圖了钦听,引以為戒—譯者注)。強(qiáng)烈推薦你在重要的函數(shù)中遵守這些傳統(tǒng)規(guī)矩倍奢。
你可以使用doc(英文狀態(tài)下的雙下劃線),這個(gè)函數(shù)的屬性來訪問printMax的文檔字符串垒棋。(作者在此提到卒煞,Python視一切為對象,函數(shù)自然不例外叼架。所以這里可以使用.點(diǎn)來(使用)函數(shù)對象的屬性畔裕,這些以后會(huì)學(xué)習(xí))
如果你在Python內(nèi)使用過help()衣撬,那么你已經(jīng)看到了文檔字符串的使用方法。它只不過就是使用函數(shù)的doc屬性扮饶,并用整潔的方法展示出來具练。你可以用help(printMax)來試驗(yàn),看看返回什么甜无。如果是在交互編輯器扛点,一般的按下‘q’鍵就退出了help界面。
(還有一點(diǎn)關(guān)于docString岂丘,略去不翻譯了陵究。有興趣的參見英文原版。)
總結(jié)
我們已經(jīng)學(xué)習(xí)了很多函數(shù)的方面奥帘,但是并沒有涵蓋函數(shù)的所有方面铜邮。當(dāng)然,我們已經(jīng)覆蓋了絕大多數(shù)日常使用有關(guān)函數(shù)的使用方法寨蹋。
下一章節(jié)松蒜,我們將學(xué)習(xí)如何使用和創(chuàng)建Python模塊。