---恢復內容開始---
一 數學定義的函數與python中的函數
初中數學函數定義:一般的,在一個變化過程中,如果有兩個變量x和y,並且對於x的每一個確定的值,y都有唯一確定的值與其對應,那么我們就把x稱為自變量,把y稱為因變量,y是x的函數。自變量x的取值范圍叫做這個函數的定義域
例如y=2*x
python中函數定義:函數是邏輯結構化和過程化的一種編程方法。
python中函數定義方法: 2 3 def test(x): 4 "The function definitions" 5 x+=1 6 return x 7 8 def:定義函數的關鍵字 9 test:函數名 10 ():內可定義形參 11 "":文檔描述(非必要,但是強烈建議為你的函數添加描述信息) 12 x+=1:泛指代碼塊或程序處理邏輯 13 return:定義返回值 調用運行:可以帶參數也可以不帶 函數名()
補充:
1、編程語言中的函數與數學意義是截然不同的概念,編程語言中的函數是通過一個函數名封裝好一串,用來完成某一特定功能的邏輯,數學定義的函數就是一個等式,等式在傳入因變量值x不同會得到一個結果y,這一點與編程語言中類似(也是傳入一個參數,得到一個返回值),不同的是數學意義的函數,傳入值相同,得到的結果必然相同且沒有任何變量的修改(不修改狀態),而編程語言中的函數傳入的參數相同返回值可不一定相同且,可以修改其他的全局變量值(因為一個函數a的執行可能依賴於另外一個函數b的結果,b可能得到不同結果,那即便是你給a傳入相同的參數,那么a得到結果肯定也不同)
2、函數式編程就是:先定義一個數學函數,然后按照這個數學模型用編程語言去實現它,至於具體如何實現和怎么做的好處,且看后續的函數式編程
二 為何使用函數
背景提要
現在老板讓你寫一個監控程序,監控服務器的系統狀況,當cpu\memory\disk等指標的使用量超過閥值時即發郵件報警,你掏空了所有的知識量,寫出了以下代碼
while True: 2 if cpu利用率 > 90%: 3 #發送郵件提醒 4 連接郵箱服務器 5 發送郵件 6 關閉連接 7 8 if 硬盤使用空間 > 90%: 9 #發送郵件提醒 10 連接郵箱服務器 11 發送郵件 12 關閉連接 13 14 if 內存占用 > 80%: 15 #發送郵件提醒 16 連接郵箱服務器 17 發送郵件 18 關閉連接
三 函數和過程
過程定義:過程就是簡單特殊沒有返回值的函數
這么看來我們在討論為何使用函數的的時候引入的函數,都沒有返回值,沒有返回值就是過程,沒錯,但是在python中有比較神奇的事情
1 def test01(): 2 msg='hello The little green frog' 3 print msg 4 5 def test02(): 6 msg='hello WuDaLang' 7 print msg 8 return msg 9 10 11 t1=test01() 12 13 t2=test02() 14 15 16 print 'from test01 return is [%s]' %t1 17 print 'from test02 return is [%s]' %t2
總結:當一個函數/過程沒有使用return顯示的定義返回值時,python解釋器會隱式的返回None,
所以在python中即便是過程也可以算作函數。
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 15 print 'from test01 return is [%s]: ' %type(t1),t1 16 print 'from test02 return is [%s]: ' %type(t2),t2 17 print 'from test03 return is [%s]: ' %type(t3),t3
返回值數=0:返回None
返回值數=1:返回object
返回值數>1:返回tuple
四 函數參數
1.形參變量只有在被調用時才分配內存單元,在調用結束時,即刻釋放所分配的內存單元。因此,形參只在函數內部有效。函數調用結束返回主調用函數后則不能再使用該形參變量
2.實參可以是常量、變量、表達式、函數等,無論實參是何種類型的量,在進行函數調用時,它們都必須有確定的值,以便把這些值傳送給形參。因此應預先用賦值,輸入等辦法使參數獲得確定值
3.位置參數和關鍵字(標准調用:實參與形參位置一一對應;關鍵字調用:位置無需固定)
4.默認參數
5.參數組
五 局部變量和全局變量
name='lhf' 2 3 def change_name(): 4 print('我的名字',name) 5 6 change_name() 7 8 9 def change_name(): 10 name='帥了一筆' 11 print('我的名字',name) 12 13 change_name() 14 print(name) 15 16 17 18 def change_name(): 19 global name 20 name='帥了一筆' 21 print('我的名字',name) 22 23 change_name() 24 print(name)
六 前向引用之'函數即變量'
def action(): 2 print 'in the action' 3 logger() 4 action() 5 報錯NameError: global name 'logger' is not defined 6 7 8 def logger(): 9 print 'in the logger' 10 def action(): 11 print 'in the action' 12 logger() 13 14 action() 15 16 17 def action(): 18 print 'in the action' 19 logger() 20 def logger(): 21 print 'in the logger' 22 23 action()
七 嵌套函數和作用域
看上面的標題的意思是,函數還能套函數?of course
1 name = "Alex" 2 3 def change_name(): 4 name = "Alex2" 5 6 def change_name2(): 7 name = "Alex3" 8 print("第3層打印",name) 9 10 change_name2() #調用內層函數 11 print("第2層打印",name) 12 13 14 change_name() 15 print("最外層打印",name)
此時,在最外層調用change_name2()會出現什么效果?
沒錯, 出錯了, 為什么呢?
作用域在定義函數時就已經固定住了,不會隨着調用位置的改變而改變
1 例一: 2 name='alex' 3 4 def foo(): 5 name='lhf' 6 def bar(): 7 print(name) 8 return bar 9 10 func=foo() 11 func() 12 13 14 例二: 15 name='alex' 16 17 def foo(): 18 name='lhf' 19 def bar(): 20 name='wupeiqi' 21 def tt(): 22 print(name) 23 return tt 24 return bar 25 26 func=foo() 27 func()()
八 遞歸
在函數內部,可以調用其他函數。如果一個函數在內部調用自身本身,這個函數就是遞歸函數。
def calc(n): 2 print(n) 3 if int(n/2) ==0: 4 return n 5 return calc(int(n/2)) 6 7 calc(10) 8 9 輸出: 10 10 11 5 12 2 13 1
#_*_coding:utf-8_*_ __author__ = 'Linhaifeng' import time person_list=['alex','wupeiqi','yuanhao','linhaifeng'] def ask_way(person_list): print('-'*60) if len(person_list) == 0: return '沒人知道' person=person_list.pop(0) if person == 'linhaifeng': return '%s說:我知道,老男孩就在沙河匯德商廈,下地鐵就是' %person print('hi 美男[%s],敢問路在何方' %person) print('%s回答道:我不知道,但念你慧眼識豬,你等着,我幫你問問%s...' %(person,person_list)) time.sleep(3) res=ask_way(person_list) # print('%s問的結果是: %res' %(person,res)) return res res=ask_way(person_list) print(res)
遞歸特性:
1. 必須有一個明確的結束條件
2. 每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減少
3. 遞歸效率不高,遞歸層次過多會導致棧溢出(在計算機中,函數調用是通過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞歸調用的次數過多,會導致棧溢出)
堆棧掃盲http://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.html
尾遞歸優化:http://egon09.blog.51cto.com/9161406/1842475
data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35] def binary_search(dataset,find_num): print(dataset) if len(dataset) >1: mid = int(len(dataset)/2) if dataset[mid] == find_num: #find it print("找到數字",dataset[mid]) elif dataset[mid] > find_num :# 找的數在mid左面 print("\033[31;1m找的數在mid[%s]左面\033[0m" % dataset[mid]) return binary_search(dataset[0:mid], find_num) else:# 找的數在mid右面 print("\033[32;1m找的數在mid[%s]右面\033[0m" % dataset[mid]) return binary_search(dataset[mid+1:],find_num) else: if dataset[0] == find_num: #find it print("找到數字啦",dataset[0]) else: print("沒的分了,要找的數字[%s]不在列表里" % find_num) binary_search(data,66)
九 匿名函數
匿名函數就是不需要顯式的指定函數
1 #這段代碼 2 def calc(n): 3 return n**n 4 print(calc(10)) 5 6 #換成匿名函數 7 calc = lambda n:n**n 8 print(calc(10))
你也許會說,用上這個東西沒感覺有毛方便呀, 。。。。呵呵,如果是這么用,確實沒毛線改進,不過匿名函數主要是和其它函數搭配使用的呢,如下
1 l=[3,2,100,999,213,1111,31121,333] 2 print(max(l)) 3 4 dic={'k1':10,'k2':100,'k3':30} 5 6 7 print(max(dic)) 8 print(dic[max(dic,key=lambda k:dic[k])])