標籤:物件導向 stack 一個 記憶體 有一個 返回 儲存狀態 引用 tac
一、函數
1、函數定義:函數是邏輯結構化和過程化的一種編程方法
函數構成:
1 python中函數定義方法: 2 def test(x): 3 "The function definitions" 4 x+=1 5 return x 6 def:定義函數的關鍵字 7 test:函數名 8 ():內可定義形參 9 "":文檔描述(非必要,建議為函數添加描述資訊)10 x+=1:泛指代碼塊或程式處理邏輯11 return:定義傳回值12 13 函數調用運行:可以帶參數也可以不帶參數
2、函數和過程
過程:就是沒有返回傳回值的函數,嚴格意義上說,在python中沒有過程,因為python中沒有值會直接返回一個None!
3、使用函數的好處
(1)、代碼重用
(2)、保持一致性,易維護
(3)、可擴充性
4、函數的參數
(1)、形參變數只有在被調用時才分配記憶體單元,在調用結束時,即刻釋放所分配的記憶體單元。因此,形參只有在函數內部有效。函數調用結束返回主調函數後則不能再使用該形參變數
(2)、實參可以是常量、變數、運算式、函數等,無論實參是何種類型的變數,在進行函數調用時,他們必須有確定的值,以便把這些值傳送給形參。因此應預先用賦值、輸入等辦法使參數獲得確定值
def chengji(x,y): # x,y 為形參 res = x**y return resa = chengji(3,4) # 3,4為實參print(a)
(3)、位置參數和關鍵字(標準調用:實參和形參位置一一對應;關鍵字調用:位置無需固定)
a、位置參數,參數必須一一對應,缺一不行,多一也不行
b、關鍵字參數,無需一一對應,缺一不行,多一夜不行
c、位置參數和關鍵字參數混用的時候,位置參數必須卸載關鍵字參數左邊不然會報錯
def xianxin(x,y,z): res = x+3*y-2*z return resa = xianxin(8,1,2.3) print(a) #6.4 def xianxin(x,y,z): res = x+3*y-2*z return res#TypeError: xianxin() takes 3 positional arguments but 4 were given#形參為3個x,y,z,調用函數的時候實參為4個,就出現上述報錯# a = xianxin(8,1,2.3,1)#TypeError: xianxin() missing 1 required positional argument: ‘z‘#形參為3個x,y,z,調用函數的時候實參為2個,就出現上述報錯a = xianxin(8,1)print(a)
(4)、預設參數
1 def handle(x,oraclename=‘orcl‘): 2 print(x,oraclename) 3 a = handle(‘hello world‘) #oraclename在調用的時候賦值,預設為orcl 4 print(a) #輸出結果:hello world orcl None 5 #為什麼會hello world orcl後會接著輸出一個None呢?因為在定義handle函數的時候沒有return傳回值,在python中沒有定義傳回值 6 #就會預設返回None; 7 8 9 10 def handle(x,oraclename=‘orcl‘):11 print(x,oraclename)12 return True13 #Welcone to: Python #True14 print(handle(‘Welcone to:‘,oraclename = ‘Python‘))
(5)、參數組
def test(x,*y): print(x) #1 print(y)#(2, 3, 4, 5, 6) print(y[0]) #2print(test(1,{2,3,4,5,6}))def test(x,*y): print(x) #1 #如果傳入的是一個列表或者字典,直接將列表或者字典作為一個元素放入元組中 print(y) #([2, 3, 4, 5, 6],) print(y[0])[2, 3, 4, 5, 6]print(test(1,[2,3,4,5,6]))
備忘:上面是將整個列表或者字典作為一個元素傳值給形參那如果我傳入的是個列表,我只想將列表裡面的元素傳給形參呢
1 def test(x,*y):2 print(x) #13 print(y) #(1, 2, 3, 4)4 test(1,*[1,2,3,4])
直接在傳入的列表實參前面加一個“*”,就可以將列表裡面的元素傳值給形參
備忘: **kwargs:**{},可以將字典裡面的元素傳值給形參
1 def test(x,**kwargs): 2 print(x)#x 3 print(kwargs)#{‘y‘: 2, ‘z‘: 3} 4 test(1,y = 2,z = 3) 5 6 def test(x,**kwargs): 7 print(x)#1 8 print(kwargs)#{‘z‘: 2, ‘y‘: 3} 9 test(1,**{‘z‘:2,‘y‘:3})10 11 def test(x,**kwargs):12 print(x)13 print(kwargs)#TypeError: test() takes 1 positional argument but 2 were given14 test(1,{‘z‘:2,‘y‘:3})
*args:*[],可以將列表裡面的元素傳值給形參;接收可變長度的值,主要的作用是用於後期的擴充,及不確定調用的介面到底有多少個參數
1 def test(x,*y):2 print(x) #13 print(y) #(1, 2, 3, 4)4 test(1,*[1,2,3,4])
備忘:那兩個混用呢,不能違背一個大的前提,位置參數必須要在關鍵字參數的左邊,不然後報錯, *args和**kwarg混用也是遵循這個原則的
def test(x,*args,**kwargs): print(x)#1 print(args)# print(kwargs)#(‘a‘, ‘b‘)test(1,‘a‘,‘b‘,y=1,z=1) #{‘y‘: 1, ‘z‘: 1}def test(x,*args,**kwargs): print(x)#1 print(args)#(1, 2, 3, 4, 5) print(kwargs)#{‘z‘: 1, ‘y‘: 2}test(1,*[1,2,3,4,5],**{‘z‘:1,‘y‘:2})
二、局部變數與全域變數
1、全域變數:全域範圍
在函數中修改全域變數修飾詞語:global
1 name = ‘zhuliye‘2 def change_name():3 global name4 name = ‘zhuyintai‘5 print(‘My name is ‘,name) #My name is zhuyintai6 change_name()7 #在調用了change_name函數後,全域變數name的值為"zhuyintai"8 print(name) #zhuyintai
2、局部變數:局部範圍
nolocal修飾的是上一級變數
3、函數即變數——前向引用
三、函數遞迴
1、死迴圈
首先來看下列代碼:運行下列代碼,報錯:“進入了死迴圈”,因為在函數調用自身的時候沒有一個明確借結束的條件,所以出現死迴圈,造成記憶體溢出
1 def calc(n):2 print(n)3 calc(n)4 calc(10) #RecursionError: maximum recursion depth exceeded while calling a Python object
2、函數遞迴的特點:
(1)、函數遞迴
在函數內部,可以調用其他函數,如果在調用一個函數直接或間接調用自身就是函數遞迴
(2)、函數遞迴的特點
a、必須要有一個明確的結束條件,不然就會出現死迴圈
b、每次進入更深一層遞迴時,問題規模相比上次遞迴都應有所減少
c、遞迴效率不高,遞迴層次過多會導致棧溢出(在電腦中,函數調用是通過棧(stack)這種資料結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞迴調用的次數過多,會導致棧溢出)
堆棧詳解:http://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.html
尾遞迴最佳化:http://egon09.blog.51cto.com/9161406/1842475
四、匿名函數lambda
1、lambda函數格式:lambda 形參:運算式
例如:lambda x :x+1
1 func = lambda x :x**22 func(10)3 #lambda函數在未調用的時候就是一串記憶體位址;4 #lambda函數一般是不會單獨存在的;5 print(func) #<function <lambda> at 0x000001641C1029D8>6 print(func(10)) #100
2、多個形參的lambda函數
1 # print(lambda name:‘name‘+‘_sb‘) 2 # res = lambda name: name+‘_sb‘ 3 # print(lambda name:‘name‘+‘_sb‘) #<function <lambda> at 0x0000019A8F812D90> 4 # print(res(‘zhangssn‘)) #zhangssn_sb 5 6 7 # res1 = lambda x,y,z:2*x+3*y-z 8 # print(res1(10,2,-1)) #27 還是遵循的是函數位置參數的原則 9 # print(res1(1,2,z=3))#5 位置參數和關鍵字參數10 11 res2 = lambda x,y,z :(x+1,y+2,z+3)12 print(res2(10,2,4)) #(11, 4, 7)
五、函數式編程
編程的三種方法論
1、物件導向編程;
2、函數式編程;
3、物件導向編程;
1、面向過程
找到解決問題的入口,按照一個固定的流程去類比解決問題的流程
例子:
a、搜尋目標,使用者輸入(配偶要求),按照要求到資料結構(字典)內檢索符合要求的人物
b、表白,表白成功進入3,否則進入2;
c、戀愛,戀愛成功進入4,否則返回1;
d、見家長,家長同意進入5,家長說他是你失散多年的妹妹,返回1;
e、結婚
1 def res(x,y):2 res1 = 2*x #13 res2 = res1-y #24 res3 = res2*2#35 return res36 res(2,1)7 print(res(2,1))
2、函數式編程:
函數式編程:函數式=程式設計語言定義的函數+數學意義的函數
函數式就是用程式設計語言去實現數學函數。這種函數內對象是永恒不變的,要麼參數是函數,要麼傳回值是函數,沒有for和while迴圈,所有的迴圈都是由遞迴去實現的,無變數的賦值(即不用變數去儲存狀態),無賦值即不改變。
(1)、特點
a、不可變的資料——不用變數儲存狀態,不修改變數
b、第一類對象——函數名可以當做參數傳遞,傳回值可以是函數名
c、尾調用最佳化(尾遞迴)
3、物件導向
python之函數