第四篇 函數
函數可以實現代碼的復用,對於多次調用的代碼片段可以封裝成函數以便於調用和後期維護。
1.定義函數與調用
1 def 函數名(參數): 2 函數體 3 return 返回值
註:
1.def是定義函數關鍵詞,def和函數名之間需要有空格。
2.函數名為函數的名字,函數名可以為字符,數字和下劃線,但是不能以數字開頭。
3.參數為調用函數需要傳入的參數。
4.返回值為調用函數後返回的值,不寫return,默認返回None。
實例:
1 def sum(a,b): 2 return a+b 3 4 sum=sum(12,13) 5 print(sum) 6 7 ------輸出結果------ 825
註:調用函數直接使用函數名()即可,當然當函數需要參數時,需要在括號內傳入指定的參數。
2.函數的返回值
函數的返回值就是調用函數後返回的值,如果函數中沒有return關鍵字,則該函數默認返回None。
1)沒有返回值
1 def sum(a,b): 2 s=a+b 3 4 s=sum(12,13) 5 print(s) 6 7 ------輸出結果------ 8 None
註:sum函數中沒有return返回值,該函數默認返回了None,另外當return關鍵字後沒有值,函數也是返回None,此用法常用來結束函數。
2)返回一個值
1 def sum(a,b):2 s=a+b 3 return s 4 5 s=sum(12,13) 6 print(s) 7 8 -----輸出結果----- 9 25
註:sum函數中返回了一個值s,然後把該值賦予s,並輸出s的值。
3)返回多個值
1 def demoReturnMul(): 2 return 1,"1,2",[1,2,3] 3 4 print(demoReturnMul()) 5 6 -------輸出結果------ 7 (1, ‘1,2‘, [1, 2, 3])
註:可以看出,函數返回多個值,是以元組的形式返回的,實際上python把多個逗號分隔的值認為是元組。可以使用多個值進行接收,但是接收的變量的個數要與返回的值的個數相等。
3.函數的參數
1)形參和實參
形參是在定義函數時函數中的參數,實參是調用函數中傳遞給函數的參數。
2)多個參數
函數可以定義多個參數,每個參數之間使用逗號分隔。
1 #a,b,c,d均為參數 2 def sum(a,b,c,d): 3 return a+b+c+d 4 5 print(sum(1,2,3,4)) 6 7 -------輸出結果------ 8 10
3)位置參數
調用函數時根據定義函數時定義的參數來傳遞參數。
1 def hello_name(name,sex): 2 dicts={‘1‘:‘男士‘,‘2‘:‘女士‘} 3 print(‘hello %s %s,welcome you‘ %(name,dicts.get(sex))) 4 5 hello_name("zhangsan",‘1‘) 6 7 --------輸出結果------- 8 hello zhangsan 男士,welcome you
4)默認參數
定義函數時為函數提供默認參數,可以在調用函數時不傳遞該參數值,函數自動取該默認值,位置參數必須位於默認值參數前面。
1 def hello_name(name,sex=‘2‘): 2 dicts={‘1‘:‘男士‘,‘2‘:‘女士‘} 3 print(‘hello %s %s,welcome you‘ %(name,dicts.get(sex))) 4 5 hello_name("zhangsan") 6 7 ------輸出結果------ 8 hello zhangsan 女士,welcome you
5)動態參數
函數參數前有一個*,則函數把參數值轉換為一個元組,函數參數前有兩個*,則函數把參數值轉換為一個字典。
1 def print_name(*args): 2 print(args) 3 4 print_name("zhangsan","lisi","wangwu","zhangliu") 5 6 ------輸出結果---- 7 (‘zhangsan‘, ‘lisi‘, ‘wangwu‘, ‘zhangliu‘)
1 def print_name(**kwargs): 2 print(kwargs) 3 4 print_name(name="zhangsan",age=18,sex=‘male‘) 5 6 ---------輸出結果----- 7 {‘age‘: 18, ‘sex‘: ‘male‘, ‘name‘: ‘zhangsan‘}
4.命名空間和作用域
1)命名空間
命名空間定義:變量名到對象的映射,各個命名空間是獨立的關系,一個命名空間不能相同的變量名,不同的命名空間可以有相同的變量名。
命名空間分類:
1.全局命名空間:程序一運行就創建的命名空間。
2.局部命名空間:程序運行過程中創建的臨時命名空間,如函數和類等。
3.內置命名空間:程序運行加載代碼前創建的命名空間,用於存放python常用內置方法。
命名空間加載順序:
內置命名空間(程序運行加載代碼前)----全局命名空間(程序運行過程中,從上往下)----局部命名空間(程序運行中,從上往下)
命名空間取值順序:
1.在局部調用:局部命名空間----全局命名空間----內置命名空間
1 i=1 2 def func(): 3 i=2 4 print(i) 5 6 func() 7 8 -------輸出結果------ 9 2
2.在全局調用:全局命名空間----內置命名空間
1 print(len(‘hello‘)) #沒有自己定義len方法,調用的是系統內置的len方法 2 3 -----輸出結果------ 4 5
1 def len(o): #自己定義的len方法 2 return "調用的是非內置方法" 3 4 print(len(‘hello‘)) #由於調用順序是全局命名空間,然後是內置命名空間,因此此處是調用自己定義的len方法 5 6 ------輸出結果------- 7 調用的是非內置方法
2.作用域
全局作用域:包括內置命名空間和全局命名空間,在整個文件中均可被調用,如果調用的位置在全局命名空間的前面,則調用的是內置命名空間的內容(如果有的話)。
1 print(len(‘hello‘)) #因為自定義的方法在調用的方法後面,調用的是系統內置方法 2 3 def len(o): 4 return "調用的是非內置方法" 5 6 ------輸出結果------ 7 5
局部作用域:包括局部命名空間,只能在局部範圍內有效。
global:用來聲明一個全局變量,在局部作用域中想要對全局變量進行修改時可以使用此關鍵詞進行聲明。
1 i=1 2 def func(): 3 i+=1 4 print(i) 5 6 func() 7 8 -----輸出結果----- 9 UnboundLocalError: local variable ‘i‘ referenced before assignment
上面報錯了,因為i為全局變量,但是在func方法中對該變量進行修改,會認為是局部變量,但是i在局部中沒有進行定義,因此會報錯,可以在函數內把i聲明為全局變量,這樣就不會報錯了。
1 i=1 2 def func(): 3 global i 4 i+=1 5 print(i) 6 7 func() 8 9 ------輸出結果------ 10 2
nonlocal:嵌套函數中內部函數修改外部變量的值。
1 def outsideFunc(): 2 i=2 3 def insideFunc(): 4 i+=2 5 print(i) 6 insideFunc() 7 outsideFunc() 8 9 ------輸出結果------ 10 UnboundLocalError: local variable ‘i‘ referenced before assignment
可以看出在內部函數中想要對外部函數的變量進行修改,會報錯,在內部函數中修改外部函數變量進行修改python會默認把變量進行隱藏,可以使用nonlocal關鍵詞進行聲明。
1 def outsideFunc(): 2 i=2 3 def insideFunc(): 4 nonlocal i 5 i+=2 6 print(i) 7 insideFunc() 8 outsideFunc() 9 10 -----輸出結果----- 11 4
註:global和nonlocal的區別是global聲明的變量為全局變量,而nonlocal聲明的變量為外部函數的變量。
5.函數名的本質
函數名的本質實際上就是函數的內存地址。
1 def func(): 2 pass 3 4 print(func) 5 6 -----輸出結果---- 7 <function func at 0x000002118E5C00D0>
1)函數名可以賦值給其他變量
1 def func(): 2 print("函數調用了。。。") 3 4 a=func 5 a() 6 7 ------輸出結果----- 8 函數調用了。。。
2)函數名可以當作容器類的元素
1 def func1(): 2 print("func1函數調用了。。。") 3 def func2(): 4 print("func2函數調用了。。。") 5 def func3(): 6 print("func3函數調用了。。。") 7 8 lists=[func1,func2,func3] 9 10 for i in lists: 11 i() 12 13 -------輸出結果----- 14 func1函數調用了。。。 15 func2函數調用了。。。 16 func3函數調用了。。。
3)函數名可以當作參數傳遞給其他函數
1 def func1(): 2 print("func1調用了") 3 4 def func2(func1): 5 func1() 6 7 func2(func1) 8 9 ------輸出結果----- 10 func1調用了
4)函數名可以當作返回值
1 def func1(): 2 print("func1調用了") 3 4 def func2(fun): 5 return fun 6 7 f=func2(func1) 8 f() 9 10 ----輸出結果----- 11 func1調用了
6.閉包
閉包的定義:內部函數對外部函數非全局變量的引用,並且外部函數返回內部函數的引用(內存地址)。
實例:
1 def outside(): 2 i=10 3 def inside(): 4 5 print(i) 6 return inside 7 8 inside=outside() #inside保存了內函數的內存地址 9 inside() 10 11 -----輸出結果----- 12 12
使用__closure__判斷函數是不是閉包函數:
1 def outside(): 2 i=10 3 def inside(): 4 print(i) 5 print(inside.__closure__) 6 return inside 7 8 inside=outside() 9 inside() 10 11 -----輸出結果---- 12 (<cell at 0x000001F028D36D68: int object at 0x000000005B1E02F0>,) 13 10
第四篇 函數