Python基礎函數、遞歸、內置函數
一、數學定義中的函數與Python中的函數
初中數學定義:一般的,在一個變化過程中,如果有兩個變量x和y,並且對於x的每一個確定值,y都有唯一確定的值與之對應,那麽我們就把x稱為自變量,把y稱為因變量,與是x的函數。自變量x的取值範圍叫做這個函數的定義域。
例如:y=2*x
python中函數的定義:函數是邏輯結構化和過程化的一種編程方法。
# Python中函數定義方法 def test(x): "the function definitions" x+=1 return x def :定義函數的關鍵字 test:函數名 ():內可定義形參 “” :文檔描述(非必要,但是強烈建議為你的函數添加描述信息) x+=1 :泛指代碼塊或程序處理邏輯 return :定義返回值 調用運行:可以帶參數也可以不帶 函數名()
補充:
1.編程語言中的函數與數學意義的函數是截然不同的兩個概念,編程語言中的函數是通過一個函數名封裝好一串用來完成某一特定功能的邏輯,數學定義的函數就是一個等式,等式在傳入因變量值x不同會得到一個結果y,這一點與編程語言中類似(也是傳入一個參數,得到一個返回值),不同的是數學意義的函數,傳入值相同,得到的結果必然相同且沒有任何變量的修改,而編程語言中的函數傳入的參數相同返回值可不一定相同且可以修改其他全局變量的值(因為一個函數a的執行可能依賴於另一個函數b的結果,b可能得到不同的結果,那即便你給a傳入相同的參數,那麽a得到的結果也肯定不同)
2.函數式編程:先定義一個數學函數(數學建模),然後按照這個數學模型用編程語言去實現它。至於具體如何實現和這麽做的好處、且看後續函數式編程。
二、為何使用函數
背景提要:
現在老板讓你寫一個監控程序,監控服務器的系統狀況、當CPU、Memory、Disk等指標的使用量超過閾值時即發郵件報警,你寫出了如下代碼
while True: if cpu利用率 >90%: #發送郵件提醒 連接郵箱服務器 發送郵件 關閉連接 if 硬盤使用空間>90% #發送郵件提醒連接郵箱服務器 發送郵件 關閉連接 if 內存占用率 >80% #發送郵件提醒 連接郵箱服務器 發送郵件 關閉連接
上述代碼實現了功能,但存在兩個主要問題:
1、代碼重復過多。一個勁的copy and paste不符合高端程序的研發標準
2、如果日後需要修改發郵件這段代碼,比如加入群發功能,那你就需要在所有用到這段代碼的地方修改一遍。
代碼修復成如下的樣子,會好的多
def 發送郵件(內容): #發送郵件提醒 連接郵箱服務器 發送郵件 關閉連接 while True: if cpu利用率>90% 發送郵件(’CPU報警‘) if 硬盤使用空間 > 90% 發送郵件(’硬盤報警’) if 內存占用 > 80% 發送郵件(‘內存報警’)
使用函數的好處:
1、代碼重用性好
2、保持一致性、易於維護
3、可擴展性強
三、函數和過程
過程的定義:過程就是簡單特殊沒有返回值的函數
這麽看來我們在討論為何使用函數的時候引入的函數,都沒有返回值,沒有返回值就是過程,但是在python中會有如下的現象發生
1 def test01(): 2 msg=‘hello The little green frog‘ 3 print msg 4 5 def test02(): 6 msg = ‘hello Mr Wang‘ 7 print msg 8 return msg 9 10 t1=test01() 11 t2=test02() 12 13 print ‘from test01 return is [%s]‘ %t1 14 print ‘from test02 return is [%s]‘ %t2
總結:當一個函數/過程沒有使用return顯示定義返回值時,python解釋器會隱式的返回None,所以在python中即便是過程也算作函數。
1 def test01(): 2 pass 3 4 def test02(): 5 return 0 6 7 def test03(): 8 return 0,10,‘hello‘,[‘Alex‘,‘lb‘],{‘WuDaLang‘:‘lb‘} 9 10 t1=test01() 11 t2=test02() 12 t3=test03() 13 14 print ‘from test01 return is [%s]:‘ %type(t1),t1 15 print ‘from test02 return is [%s]:‘ %type(t2),t2 16 print ‘from test03 return is [%s]: %type(t3),t3
總結:
返回值數=0:返回None
返回值數=1:返回Object
返回值數>1:返回tuple
四、函數參數
1、形參變量只有在被調用時才分配內存單元,在調用結束時,即可釋放所分配的內存單元。因此,形參只有在函數的內部有效,函數調用結束返回主調用函數後則不能再使用該形參變量。
2、實參可以是常量、變量、表達式、函數等,無論實參是何種類型的量,再進行函數調用時,它們都必須有確定的值,以便把這些值傳給行參。因此,應預先賦值,輸入等辦法使參數獲得確定的值。
3、位置參數與關鍵字參數
4、默認參數
5、參數組
五、局部變量和全局變量
在子程序中定義的變量稱為局部變量,在程序一開始定義的變量稱為全局變量。全局變量的作用域是整個程序,局部變量作用域是定義該變量的子程序。
當全局變量與局部變量同名時:在定義局部變量的子程序內,局部變量起作用;其他地方全局變量起作用。
六、前向引用之‘函數即變量
1 def action(): 2 print ‘in the action‘ 3 logger() 4 action() 5 #報錯nameError:gloable name ‘logger‘ is not defined 6 7 def logger(): 8 print ‘in the logger‘ 9 def action(): 10 print ‘in the action‘ 11 logger() 12 action() 13 14 def action(): 15 print ‘in the action‘ 16 logger() 17 def logger(): 18 print ‘in the logger()‘ 19 action()
七、嵌套函數和作用域
1 name="Alex" 2 3 def change_name(): 4 name="Alex2" 5 def change_name2(): 6 name="Alex3" 7 print("第三層打印“,name) 8 9 10 change_name2() 11 print("第二層打印”,name) 12 change_name() 13 print("最外層打印“,name)
此時,在最外層調用chang_name2()會出現什麽效果,報錯了,作用域在定義函數式就已經被固定了,不會隨著位置的改變而改變。
八、遞歸和調用
在函數內部,可以調用其他函數,如果在調用一個函數的過程中直接或間接調用自身本身
1 def cal(n): 2 print(n) 3 if int(n/2)==0 4 return n 5 return cal(int (n/2)) 6 7 cal(10)
遞歸的特性:
1、必須有一個明確的結束條件
2、每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減少
3、遞歸效率不高,遞歸層次過多或導致棧溢出
九、匿名函數
匿名函數就是不需要顯式的指定函數
# 這段代碼 def calc(n): return n**n print(cal(10)) # 換成匿名函數 calc = lambda n : n**n print(calc(10))
你也許會說,用上面這個東西沒感覺方便,匿名函數主要是和其他函數搭配使用的,如下
l= [3,2,100,999,213,1111,31121,333] print(max(l)) dic={‘k1‘:10,‘k2‘:100,‘k3‘:30} print(max(dic)) print(dic[max(dic,key=lambda k:dic[k])]) res= map(lambda x:x**2,[1,5,7,4,8]) for i in res : print(i)
十、函數式編程
通俗的理解:函數的參數傳入,是函數吃進去的食物,而函數return的返回值,是函數拉出來的結果,面向過程的思路就是:把程序的執行當成一串首尾相連的函數,一個函數吃,拉出來的東西給另一個函數吃,另一個函數吃了再繼續拉給下一個函數吃。。。
例如用戶登錄程序:
前端接收處理用戶請求-->將用戶信息傳給邏輯層-->將用戶的信息寫入數據庫
高階函數:
滿足如下特征之一的函數就是高階函數:1、函數的傳入參數是一個函數名。2、函數的返回值是一個函數名
十一、內置函數
略
Python基礎函數、遞歸、內置函數