python的函數(shù)最詳解
一、函數(shù)入門(mén)
1.概念
- 函數(shù)是可以重復(fù)執(zhí)行一定任務(wù)的代碼片段,具有獨(dú)立的固定的輸入輸出接口。
- 函數(shù)定義的本質(zhì),是給一段代碼取個(gè)名字,方便以后重復(fù)使用
- 為了方便以后調(diào)用這個(gè)函數(shù),在定義它的時(shí)候,就需要明確它的輸入(參數(shù))與輸出(返回值)
2.定義函數(shù)的語(yǔ)法格式
def 函數(shù)名(形參列表): #可執(zhí)行語(yǔ)句 return 返回值
函數(shù)名
- 只要是合法的標(biāo)識(shí)符即可(同變量命名)
- 為了提高可讀性,建議函數(shù)名由一個(gè)或多個(gè)有意義的單詞組成,單詞之間用下劃線_分隔,字母全部小寫(xiě)
形參列表
- 在函數(shù)名后面的括號(hào)內(nèi),多個(gè)形參用逗號(hào)分隔,可以沒(méi)有參數(shù)
- 參數(shù)可以有默認(rèn)值,可以用等號(hào)=直接指定默認(rèn)值,有默認(rèn)值的參數(shù)必須排最后
- 沒(méi)有默認(rèn)值的參數(shù),在調(diào)用的時(shí)候必須指定
- 形參也可以沒(méi)有,但是括號(hào)不能省略
- 調(diào)用有默認(rèn)值的參數(shù)要指定名字
返回值
- 返回值可以沒(méi)有,直接省略return這句話
- 返回值可以是一個(gè)或多個(gè),用逗號(hào)分隔,組合成一個(gè)元組
- 返回值還可以是表達(dá)式
- 多個(gè)返回值,不需要的用下劃線頂替!
3.函數(shù)的文檔(注釋→help)
- 一段被注釋的文字對(duì)函數(shù)進(jìn)行解釋。
- 可以用help()查看函數(shù)的文檔,只要把一段字符串緊接著放在函數(shù)的聲明行的后面,它就可以被help識(shí)別了。
4.舉例
# 函數(shù)定義 def myfunc(arg1, arg2, arg3=None): ''' This is a example for python documentation. 這是一個(gè)為python函數(shù)提供文檔的例子。 arg1: 第一個(gè)參數(shù)的說(shuō)明 arg2: 第二個(gè)參數(shù)的說(shuō)明 arg3: 第三個(gè)參數(shù)的說(shuō)明(這個(gè)參數(shù)有默認(rèn)值) v1, v2, v3: 返回值的說(shuō)明 ''' v1 = arg1 + arg2 v2 = arg1 * arg2 if arg3 is None: v3 = arg1 + arg2 else: v3 = arg1 + arg2 + arg3 return v1, v2, v3 # 函數(shù)調(diào)用 v1, v2, v3 = myfunc(5, 3, arg3=4) print(v1, v2, v3) #8 15 12 # 使用arg3的默認(rèn)值調(diào)用函數(shù) v1, v2, v3 = myfunc(5, 3) print(v1, v2, v3) #8 15 8 # 忽略一個(gè)返回值 v1, v2, _ = myfunc(5, 3) print(v1, v2, v3) #8 15 8 # 看看返回值是元組tuple,在返回的過(guò)程中被自動(dòng)解包 print(type(myfunc(5,3))) #<class 'tuple'>
二、函數(shù)的參數(shù)
- 函數(shù)的參數(shù)是參數(shù)與外部可變的輸入之間交互的通道。
- 函數(shù)的參數(shù)名稱應(yīng)該滿足標(biāo)識(shí)符命名規(guī)范,應(yīng)該有明確的含義,可通過(guò)參數(shù)名稱知道每個(gè)參數(shù)的含義。
- 在函數(shù)定義下面的注釋中逐個(gè)注明函數(shù)(和返回值)的含義,以便用戶即使不甚了解函數(shù)中的具體內(nèi)容也能正確無(wú)誤的使用它。
- 實(shí)參:實(shí)際參數(shù),從外面?zhèn)鬟f來(lái)的實(shí)際的參數(shù)
- 形參:形式參數(shù),在函數(shù)內(nèi)部它形式上的名字
- 調(diào)用函數(shù)時(shí),實(shí)參按照順序位置與形參綁定,稱為位置參數(shù)(Positional Argument)
- 也可以在調(diào)用時(shí),寫(xiě)明實(shí)參與形參的對(duì)應(yīng)關(guān)系,稱作傳遞關(guān)鍵字參數(shù)(Keyword Argument),這時(shí)候位置信息被忽略了
- 同時(shí)傳遞位置參數(shù)與關(guān)鍵字參數(shù),應(yīng)該先傳遞位置參數(shù),再傳遞關(guān)鍵字參數(shù)!
- 函數(shù)定義的時(shí)候,可以指定默認(rèn)值,但帶默認(rèn)值的參數(shù)必須列在參數(shù)列表的最后
#舉一個(gè)小栗子,計(jì)算紙箱子的體積 def cube_volume(length, width, height = 0.25): ''' 計(jì)算紙箱子的體積(單位:m) length: 長(zhǎng); width: 寬 height: 高(默認(rèn)參數(shù)0.25) v: 返回值,紙箱的體積,單位m**3 ''' if length <= 0: print('length must larger than 0!') return 0 if width <= 0: print('width must larger than 0!') return 0 if height <= 0: print('height must larger than 0!') return 0 v = length*width*height print('length = %.2f; width = %.2f; height = %.2f; cube volume = %.2f' % \ (length, width, height, v)) return v # 使用位置參數(shù)調(diào)用 v = cube_volume(1, 2, 3) # 使用關(guān)鍵字參數(shù)調(diào)用 v = cube_volume(width = 1, height = 2, length = 3) # 位置參數(shù)和關(guān)鍵字參數(shù)混用 v = cube_volume(1, height = 2, width = 3) # 關(guān)鍵字參數(shù)在位置參數(shù)之前會(huì)報(bào)錯(cuò) # v = cube_volume(width = 1, 2, 3)
1.可變對(duì)象
- 如果參數(shù)是可變對(duì)象(如列表),函數(shù)內(nèi)部對(duì)此對(duì)象的修改會(huì)在函數(shù)執(zhí)行后仍然有效
- 如果默認(rèn)參數(shù)是可變對(duì)象,函數(shù)內(nèi)部修改了此對(duì)象后,函數(shù)默認(rèn)值也發(fā)生了改變!
- 實(shí)際函數(shù)傳遞進(jìn)去的是地址,函數(shù)體不會(huì)將地址傳遞出來(lái),但地址對(duì)應(yīng)的值發(fā)生了變化。
# 對(duì)列表的乘方運(yùn)算 def pow_list(x, p): ''' power of a list x: list p: power not return value ''' for i in range(len(x)): x[i] **= p #這樣會(huì)輸出乘方后的值,但不會(huì)改變x列表里的值 #因?yàn)樵谟?jì)算時(shí)將x中的值傳入了新的參數(shù)進(jìn)行計(jì)算 #for i in x: # i **= p # print(i) #print(x) x = [1,2,3,5,7,9,10,12] pow_list(x,2) print(x) # 可見(jiàn)函數(shù)內(nèi)部對(duì)列表x中元素的更改,當(dāng)函數(shù)退出之后依然有效
利用可變對(duì)象的特點(diǎn),可以制作一種隱藏的參數(shù)記錄器
# 隱藏的參數(shù)記錄器 def growing_list(x, y=[]): y.append(x) print(y) # 重復(fù)執(zhí)行g(shù)rowing_list(‘a(chǎn)')會(huì)發(fā)生什么結(jié)果? growing_list(2)#[2] growing_list('張三') #[2, '張三'] growing_list(22333) #[2, '張三', 22333]
2.參數(shù)收集(不定個(gè)數(shù)的參數(shù))
- 參數(shù)收集,指定是可以往函數(shù)內(nèi)傳遞不定個(gè)數(shù)的參數(shù),例如有時(shí)候傳遞3個(gè),有時(shí)候傳遞5個(gè),有時(shí)候傳遞10個(gè),等等。
- 傳遞不定個(gè)數(shù)的參數(shù),要在定義參數(shù)時(shí),加上一個(gè)星號(hào)“*”(形參為空的tuple)。
- 帶星號(hào)的參數(shù)可以位于參數(shù)列表的任意位置(不一定是開(kāi)頭也不一定是結(jié)尾),python要求一個(gè)函數(shù)只能有一個(gè)帶星參數(shù)。
# 不定個(gè)數(shù)的數(shù)字求和 def my_sum(*t): # 帶星號(hào)的輸入?yún)?shù)被當(dāng)作元組處理 print(t, type(t)) sum = 0 for s in t: sum += s return sum # 事實(shí)上該函數(shù)接受了不定個(gè)數(shù)的輸入?yún)?shù) my_sum(1,2,3,4,2233)
如果帶星參數(shù)后面還有別的參數(shù),則它們必須要用關(guān)鍵字參數(shù)的方式傳遞,否則python不知道它們到底是啥,都會(huì)給收集到帶星參數(shù)里。
# 不定個(gè)數(shù)的數(shù)字乘方后求和 def pow_sum(*t, p): # 帶星號(hào)的輸入?yún)?shù)被當(dāng)作元組處理 print(t, type(t)) sum = 0 for s in t: sum += s**p return sum # 最后一個(gè)參數(shù)p,需要指定關(guān)鍵字傳遞 pow_sum(1,2,3,4,2233,p=2) # 如果不指定關(guān)鍵字傳遞呢?會(huì)報(bào)錯(cuò) # pow_sum(1,2,3,4,2233,2)
3.解決一個(gè)實(shí)際問(wèn)題
# 不定個(gè)數(shù)的數(shù)字加權(quán)求和 # 權(quán)重隨著數(shù)字的個(gè)數(shù)而發(fā)生變化 def weighted_sum(x1,x2,*y): sum = 0 n = len(y) weight = 1/3/n for i in y: sum += weight*i return sum+1/3*x1+1/3*x2 weighted_sum(1,2,3) weighted_sum(1,2,3,22,44,55) weighted_sum(1,2,3,4,5,6)
4.參數(shù)收集(收集關(guān)鍵字參數(shù))
- python除了帶一個(gè)型號(hào)的參數(shù),還支持帶兩個(gè)星號(hào)的參數(shù)。它的功能是收集關(guān)鍵字參數(shù)。
- 一個(gè)函數(shù),至多可以帶一個(gè)一星參數(shù)(收集位置參數(shù)),加上一個(gè)二星參數(shù)(收集關(guān)鍵字參數(shù))。
- 二星參數(shù)在函數(shù)內(nèi)部以字典的形式存在。
- 二星參數(shù)必須在參數(shù)列表的末尾,它后面不能再有別的關(guān)鍵字參數(shù)和位置參數(shù)了。
# 測(cè)試一星參數(shù)和兩星參數(shù) def test_star(a, b, c, *onestar, **twostar): print('a = %d; b = %d; c = %d' % (a, b, c)) print(onestar, type(onestar)) print(twostar, type(twostar)) test_star(1, 2, 3, 4, 5, 6, s1 = 7, s2 = 8, s3 = 9) # 換個(gè)順序呢? # test_star(1, 2, 3, 4, 5, 6, s1 = 7, s2 = 8, s3 = 9, a = 10, b = 11, c = 12) # 報(bào)錯(cuò)了,二星參數(shù)后面不能再傳遞關(guān)鍵字參數(shù)了(當(dāng)然位置參數(shù)也不行)
“參數(shù)收集”功能,會(huì)讓帶星參數(shù)盡量少的收集,把更多參數(shù)留給正常的位置參數(shù)和關(guān)鍵字參數(shù)
# 如果有默認(rèn)參數(shù),要注意可能引起的bug def test_star(a, b, c, p = 5, *onestar, **twostar): print('a = %d; b = %d; c = %d; p = %d' % (a, b, c, p)) #a = 1; b = 2; c = 3; p = 4 print(onestar, type(onestar))#(5, 6) <class 'tuple'> print(twostar, type(twostar))#{'s1': 7, 's2': 8, 's3': 9} <class 'dict'> # 會(huì)傳遞一個(gè)p=4進(jìn)去,而不是設(shè)想的,onestar=(4,5,6) test_star(1, 2, 3, 4, 5, 6, s1 = 7, s2 = 8, s3 = 9)
5.逆向參數(shù)收集(炸開(kāi)參數(shù))
- 在參數(shù)外部定義好了的列表、元組、字典等,可以在傳參的時(shí)候被“炸開(kāi)”,其中的內(nèi)容被自動(dòng)分配到參數(shù)列表中
- “炸”列表或者元組,需要在前面添加一個(gè)星號(hào)。
- “炸”字典,需要在前面添加兩個(gè)星號(hào)。
# 炸參數(shù)例子 def zha(a,b,c): print(a,b,c) # 炸元組 z = (1,2,3)#1 2 3 zha(*z) # 炸列表 z = [4,5,6]#4 5 6 zha(*z) # 炸字典 z = {'a':7,'b':8,'c':9} #7 8 9 zha(**z) # 炸字典 z = {'c':7,'a':8,'b':9} #8 9 7 zha(**z) # 如果炸開(kāi)后參數(shù)個(gè)數(shù)或Key不匹配,會(huì)報(bào)錯(cuò) # z = {'c':7,'a':8} # zha(**z)
6.參數(shù)的內(nèi)存管理
- python的參數(shù)傳遞,傳遞的是參數(shù)值而非參數(shù)地址。參數(shù)值被復(fù)制后傳遞進(jìn)函數(shù)。
- 對(duì)于數(shù)值類(lèi)型的參數(shù)(整型、浮點(diǎn)、復(fù)數(shù)等),在函數(shù)內(nèi)改變參數(shù)值,函數(shù)外面不受影響。
- 對(duì)于容器類(lèi)型的參數(shù)(列表、字典、字符串等),在函數(shù)內(nèi)改變了容器里的內(nèi)容,在函數(shù)的外面也可以體現(xiàn)出來(lái)。
# 傳遞數(shù)值類(lèi)型參數(shù) # 在函數(shù)內(nèi)修改,在函數(shù)外面不受影響 def mod_para1(a,b): print('In mod_para1, before modification: a = %d; b = %d' % (a,b)) #a = 2; b = 8 a *= 2 b += 4 print('In mod_para1, after modification: a = %d; b = %d' % (a,b)) #a = 4; b = 12 a = 2 b = 8 print('Out of mod_para1, before modification: a = %d; b = %d' % (a,b)) #a = 2; b = 8 mod_para1(a,b) print('Out of mod_para1, after modification: a = %d; b = %d' % (a,b)) #a = 2; b = 8
- 傳遞容器類(lèi)型參數(shù)
- 在函數(shù)內(nèi)修改,在函數(shù)外面也能體現(xiàn),也可以用這種方法向外界傳遞信息
- 如果不希望容器類(lèi)型中的內(nèi)容被修改,請(qǐng)手動(dòng)使用copy.copy() copy.deepcopy()方法
# 列表通過(guò)函數(shù)傳參時(shí),被改動(dòng)了數(shù)據(jù) def mod_para2(x): print('In mod_para2, before modification: x = ' + str(x)) for i in range(len(x)): x[i] *= 2 print('In mod_para2, after modification: x = ' + str(x)) x = [i for i in range(10)] print('Out of mod_para2, before modification: x = ' + str(x)) mod_para2(x) print('Out of mod_para2, after modification: x = ' + str(x)) import copy A = [1,2,3]; B = copy.copy(A) mod_para2(B); print(A,B)
7.函數(shù)中變量的作用域
- 創(chuàng)建于函數(shù)外部,它是全局(Global)的,它在這個(gè)py文件內(nèi)部的任何地方可見(jiàn)。
- 創(chuàng)建于函數(shù)內(nèi)部,它是局部(Local)的,它只能在函數(shù)內(nèi)部才能訪問(wèn),在函數(shù)外部不可見(jiàn)。
- 全局變量和局部變量重名,函數(shù)內(nèi)會(huì)訪問(wèn)到局部變量,函數(shù)外訪問(wèn)到全局變量。
- 函數(shù)內(nèi)部能訪問(wèn)全局變量,但不能修改!
- 如果非要在函數(shù)內(nèi)部修改全局變量,需要聲明(不推薦這么干?。?/li>
gv1 = 1 def test(): # gv1=2 print('在函數(shù)內(nèi)部訪問(wèn)全局變量:gv1 = %d' % gv1) #1 # gv1=2 test() print('在函數(shù)外部訪問(wèn)全局變量:gv1 = %d' % gv1) #1
- 上面的例子,會(huì)在gv1 = 2的前一行,報(bào)錯(cuò),看起來(lái)匪夷所思。
- 事實(shí)上,這屬于python對(duì)全局變量的“遮蔽”(hide)操作。在python的函數(shù)內(nèi)部對(duì)不存在的變量賦值時(shí),默認(rèn)會(huì)重新定義局部變量。也就是說(shuō),在整個(gè)函數(shù)的內(nèi)部,gv1都被重新定義了,這一操作會(huì)影響整個(gè)函數(shù),因此會(huì)在它的上一行報(bào)錯(cuò)。
- 為了訪問(wèn)被遮蔽的全局變量,需要使用globals()函數(shù),將全局變量以字典的形式輸出。(globals()['全局變量名'])——或者可以簡(jiǎn)單認(rèn)為出全局變量通過(guò)globals()中的字典存儲(chǔ)
- 目前得知python3.10以后是不會(huì)報(bào)錯(cuò)了,但這種操作方法我們一般是不推薦的!
# 訪問(wèn)被遮蔽的全局變量 gv1 = 1 def test(): # 用globals函數(shù)訪問(wèn)被遮蔽的全局變量 print('在函數(shù)內(nèi)部訪問(wèn)全局變量:gv1 = %d' % globals()['gv1']) gv1 = 2 print('在函數(shù)內(nèi)部訪問(wèn)修改后的全局變量:gv1 = %d' % gv1) test() print('在函數(shù)外部訪問(wèn)全局變量:gv1 = %d' % gv1) # 函數(shù)內(nèi)部修改的其實(shí)是同名局部變量,全局變量沒(méi)有被修改。
- 正常的做法是,只要有定義全局變量,函數(shù)內(nèi)部的局部變量就不應(yīng)該和它重名!
- 可以用global語(yǔ)句,在函數(shù)內(nèi)部聲明全局變量,經(jīng)過(guò)聲明的全局變量在函數(shù)內(nèi)部可以訪問(wèn)和修改。
# 測(cè)試全局變量 gv1 = 1 def test(): global gv1 #全局變量我來(lái)?yè)慰? print('在函數(shù)內(nèi)部訪問(wèn)全局變量:gv1 = %d' % gv1) #1 gv1+=1 test() print('在函數(shù)外部訪問(wèn)全局變量:gv1 = %d' % gv1) #2
8.獲取指定范圍內(nèi)的變量
- python提供了多個(gè)方法可以讓我們?cè)L問(wèn)到每個(gè)變量的“名字”和他們持有的“值”
- 變量在內(nèi)存的某處保存著“名字”-“值”對(duì)兒
- globals(): 返回全局范圍內(nèi)所有變量組成的字典, globals()[“名字”]
- locals(): 返回當(dāng)前函數(shù)范圍內(nèi)的所有變量組成的字典
- vars(object): 獲取指定對(duì)象范圍內(nèi)的所有變量組成的字典(如果不傳入object參數(shù),vars和locals的作用完全相同)
- 如果在全局范圍內(nèi)(在函數(shù)外部)調(diào)用locals(),則它的行為和globals()一樣,也會(huì)列出全局范圍內(nèi)所有變量
- 一般來(lái)說(shuō),上述函數(shù)所列出的變量字典,都不應(yīng)該被修改!但事實(shí)上它們可以被修改!!不推薦使用這種方式修改變量。
三、局部函數(shù)(函數(shù)的嵌套)
- python可以在函數(shù)的內(nèi)部定義函數(shù),多個(gè)函數(shù)相互嵌套。在其它函數(shù)內(nèi)部的函數(shù)稱為“局部函數(shù)”。
- 局部函數(shù)是對(duì)外隱藏的,只能封閉在定義它的那一個(gè)函數(shù)的內(nèi)部使用。
- python的函數(shù)也可以作為返回值,如果把局部函數(shù)作為返回值,就可以在其它函數(shù)中使用了。
一個(gè)栗子(利用局部函數(shù)實(shí)現(xiàn)多種平均值的切換)
# 利用局部函數(shù)實(shí)現(xiàn)多種平均值的切換 def mymean(x, mtype = 'arithmetic'): '''計(jì)算列表x的平均值,用mtype定義計(jì)算哪種平均值,默認(rèn)為算術(shù)平均值(arithmetic mean) ''' def arithmetic(x): ''' 算術(shù)平均值(arithmetic mean) ''' m = sum(x)/len(x); return m def geometric(x): '''幾何平均值(geometric mean) ''' p = 1.; n = len(x) for i in range(n):p *= x[i] m = p ** (1/n); return m def harmonic(x): ''' 調(diào)和平均值(harmonic mean) ''' s = 0.;n = len(x) for i in range(n): s += 1/x[i] m = 1/(s/n); return m if mtype == 'arithmetic': return arithmetic elif mtype == 'geometric': return geometric elif mtype == 'harmonic': return harmonic else: return arithmetic
- 類(lèi)似于函數(shù)內(nèi)局部變量遮蔽全局變量,局部函數(shù)內(nèi)的變量也會(huì)遮蔽它所在函數(shù)的局部變量。
- 因此使用局部函數(shù)時(shí),同樣要注意變量名的問(wèn)題,不同層次的函數(shù)變量名應(yīng)該不同。
- 如果要訪問(wèn)上一層函數(shù)的局部變量,在局部函數(shù)中應(yīng)該用nonlocal聲明(類(lèi)比于用global聲明全局變量)。
# 局部函數(shù)內(nèi)的變量與函數(shù)內(nèi)的局部變量相沖突,這個(gè)程序會(huì)報(bào)錯(cuò) def test1(): fv = 1 def test2(): # print('局部函數(shù)內(nèi)打印上層函數(shù)中的局部變量:%d' % fv) # 會(huì)在這里報(bào)錯(cuò) fv = 2 print('局部函數(shù)內(nèi)打印上層函數(shù)中的局部變量(更改后):%d' % fv) #2 test2() print('上層函數(shù)內(nèi)打印局部變量(更改后):%d' % fv) #1 return fv print('上層函數(shù)外打印局部變量(更改后):%d' % test1()) #1
用nolocal聲明的方式可以使用/更改全局變量
# 局部函數(shù)內(nèi)的變量與函數(shù)內(nèi)的局部變量相沖突,應(yīng)該改成這樣就不報(bào)錯(cuò)了 def test1(): fv = 1 def test2(): nonlocal fv # 用nonlocal聲明,把fv聲明為上一層函數(shù)的變量 print('局部函數(shù)內(nèi)打印上層函數(shù)中的局部變量:%d' % fv) #1 fv = 2 print('局部函數(shù)內(nèi)打印上層函數(shù)中的局部變量(更改后):%d' % fv) #2 test2() print('上層函數(shù)內(nèi)打印局部變量(更改后):%d' % fv) #2 return fv print('上層函數(shù)外打印局部變量(更改后):%d' % test1()) #2
四、函數(shù)的高級(jí)內(nèi)容
- python中萬(wàn)物皆對(duì)象,函數(shù)也是對(duì)象。函數(shù)可以賦值給變量,可以作為函數(shù)的參數(shù),也可以作為函數(shù)的返回值。
- python中以函數(shù)作為對(duì)象的用法,可以類(lèi)比于c語(yǔ)言中的函數(shù)指針,但比函數(shù)指針靈活的多,也更不容易出錯(cuò)。
# 以第三章栗子中mymean函數(shù)為例 # 將函數(shù)賦值給變量f f = mymean2('arithmetic') # 打印出來(lái)看看 print(f) # 測(cè)試一下 x = list(range(1,10)) m = f(x) print(m) # 也可以像上面的例子一樣,連起來(lái)寫(xiě) print(mymean2('geometric')(x))
1.函數(shù)作為函數(shù)的形參
- 有時(shí)候需要定義一個(gè)函數(shù),讓它內(nèi)部的大致流程都固定下來(lái),但其中某些部件可以替換:類(lèi)似于汽車(chē)換發(fā)動(dòng)機(jī),電腦換顯卡。
- 這種“可替換式”的程序設(shè)計(jì)方式,在python中可以方便的通過(guò)將函數(shù)作為形參的方式來(lái)實(shí)現(xiàn)。
2.使用函數(shù)作為返回值
- 將一個(gè)函數(shù)對(duì)象(可以是局部函數(shù),也可以是別的地方定義的函數(shù))作為返回值,適合“部件替換式”程序設(shè)計(jì)中,判斷使用哪個(gè)部件。
- 具體實(shí)現(xiàn)方式參見(jiàn)第三章局部變量栗子中的代碼
# 以第三章栗子中mymean函數(shù)為例 # 編寫(xiě)另一個(gè)程序,對(duì)列表中的數(shù)字進(jìn)行變換,變成均值為1的另一個(gè)列表 # 均值,可以是算術(shù)平均值、幾何平均值、調(diào)和平均值 def mynormalize(x, mtype): f = mymean(mtype) m = f(x) return [i/m for i in x] x = list(range(1,10)) mtype = 'geometric' print(mymean(mtype)(x)) print(mynormalize(x, mtype))
3.遞歸
- 在一個(gè)函數(shù)里面調(diào)用它自己,稱為遞歸。
- 遞歸可以視作一種隱式的循環(huán),不需要循環(huán)語(yǔ)句控制也可實(shí)現(xiàn)重復(fù)執(zhí)行某段代碼。
- 遞歸在大型復(fù)雜程序中非常有用,在數(shù)值和非數(shù)值算法中都能大顯身手!
- 使用遞歸的時(shí)候要注意,當(dāng)一個(gè)函數(shù)不斷調(diào)用自己的時(shí)候,必須保證在某個(gè)時(shí)刻函數(shù)的返回值是確定的,即不再調(diào)用自己。
# 斐波那契數(shù)列(Fibonacci sequence) # 在現(xiàn)代物理、準(zhǔn)晶體結(jié)構(gòu)、化學(xué)等領(lǐng)域,斐波納契數(shù)列都有直接的應(yīng)用 def Fibonacci(n): ''' Fibonacci sequence f(0)=1, f(1) = 1, f(n) = f(n-1)+f(n-2) ''' if n == 0 or n == 1: return 1 else:return Fibonacci(n-1) + Fibonacci(n-2) # 測(cè)試一下,注意n不要設(shè)的太大,python的遞歸效率是比較低的,太大會(huì)死機(jī) print(Fibonacci(5)) # 斐波那契數(shù)列,前20位 print('Fibonacci sequence:') for i in range(20): print('%d: %d' % (i,Fibonacci(i)))
五、局部函數(shù)與lambda
- lambda表達(dá)式是現(xiàn)代編程語(yǔ)言引入的一種函數(shù)實(shí)現(xiàn)方式,它可以在一定程度上代替局部函數(shù)。
- 對(duì)于局部函數(shù),它的名字只在函數(shù)內(nèi)部有意義,在函數(shù)外部看不到它的名字。即便使用返回值的形式傳出來(lái)了,它的名字并沒(méi)有被同時(shí)傳出來(lái)。
- 從命名的意義上講,局部函數(shù)都是“隱姓埋名”的,出了這個(gè)函數(shù)就沒(méi)人知道它的名字。
- lambda表達(dá)式就相當(dāng)于匿名函數(shù)。
# 一行中的hello world greeting = lambda: print('Hello lambda!') greeting() # lambda表達(dá)式可以放在數(shù)組里面,批量運(yùn)行 L = [lambda x: x**2, lambda x: x**3, lambda x: x**4] for p in L: print(p(3))
1.用lambda表達(dá)式代替局部函數(shù)
# 用lambda表達(dá)式代替局部函數(shù) def mymean2(mtype = 'arithmetic'): ''' 返回計(jì)算平均值所用的函數(shù),用mtype定義計(jì)算哪種平均值,默認(rèn)為算術(shù)平均值(arithmetic mean) ''' # 由于lambda表達(dá)式只能寫(xiě)一行,這里用numpy和scipy的現(xiàn)成的函數(shù)來(lái)實(shí)現(xiàn) import numpy as np import scipy.stats as st a = np.array(x) if mtype == 'arithmetic': # 算術(shù)平均值(arithmetic mean) return lambda a: np.mean(a) elif mtype == 'geometric':# 幾何平均值(geometric mean) return lambda a: st.gmean(a) elif mtype == 'harmonic': # 調(diào)和平均值(harmonic mean) return lambda a: st.hmean(a) else: # 默認(rèn):算術(shù)平均值(arithmetic mean) return lambda a: np.mean(a) x = list(range(1,10)) print(x) print(mymean2('arithmetic')(x)) print(mymean2('geometric')(x)) print(mymean2('harmonic')(x))
2.常見(jiàn)數(shù)學(xué)方法的內(nèi)部函數(shù)
# 判斷所有元素是否為T(mén)rue,相當(dāng)于多重的and help(all) print(all([3>2,6<9])) # 任意一個(gè)元素是否為T(mén)rue,相當(dāng)于多重的or help(any) print(any([3>2,6<9])) # 最大值和最小值 help(max) help(min) print(max([1,2,5,3])) print(min([1,2,5,3])) # 四舍五入(到小數(shù)點(diǎn)后第n位) help(round) print(round(3.1415926,3)) # 所有元素相加 help(sum) print(sum([1,2,3])) print(sum([1,2,3],5)) # 乘冪 help(pow) print(pow(6,2)) print(pow(6,2,5)) # 帶余除法 help(divmod) print(divmod(6,2)) # 絕對(duì)值 help(abs) print(abs(-2.56))
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注本站的更多內(nèi)容!
版權(quán)聲明:本站文章來(lái)源標(biāo)注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請(qǐng)保持原文完整并注明來(lái)源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非www.sddonglingsh.com所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來(lái)源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來(lái),僅供學(xué)習(xí)參考,不代表本站立場(chǎng),如有內(nèi)容涉嫌侵權(quán),請(qǐng)聯(lián)系alex-e#qq.com處理。