Python函數知識點總結
1.函數的定義
2.如何定義一個函數以及函數語法
3.函數的調用
4.函數的參數(形參,實參)以及參數的傳遞
5.函數的返回值
6.變量的作用域
7.匿名函數
8.嵌套函數和閉包
9.裝飾器
1.函數的定義
函數是組織好的,可重復使用的,用來實現一定功能的代碼段。
函數能提高應用的模塊性,和代碼的重復利用率。
2.如何定義一個函數以及函數語法
函數代碼塊以def關鍵詞開頭,後接函數名稱和圓括號()
傳入的任何參數和自變量放在圓括號()中間
函數的內容以冒號起始,並且縮進
函數的第一行語句可以選擇性的使用文檔字符串————用於存放函數說明
return 【表達式】結束函數,選擇性的返回一個值給調用方。不帶表達式的return相當於返回None
語法:
def function_name(parameters): ‘‘‘函數說明‘‘‘ function_suite return [expression]
實例:
def print_test(str_par): ‘‘‘打印輸入的字符串到標準顯示設備上‘‘‘ print(str_par) return print_test(test_success)
3.函數的調用
定義一個函數只給了函數一個名稱,指定了函數裏包含的參數和代碼塊結構。
這個函數的基本結構完成以後,你可以通過另一個函數調用執行,也可以直接從Python提示符執行。
實例:
#!/usr/bin/python #-*- coding:UTF-8 -*- #定義函數 def print_test(str_par): ‘‘‘打印輸入的字符串到標準顯示設備上‘‘‘ print(str_par) return #調用函數 print_test(test_success)
4.函數的參數(形參,實參)以及參數的傳遞
在python中,類型屬於對象,變量是沒有類型的。
a = [1,2,3]
a = "hello,world"
以上代碼中,[1,2,3]是list類型,"hello world"是string類型,而變量a是沒有類型,她僅僅是一個對象的引用(一個指針),可以是list類型對象,也可以指定string類型對象
可更改(mutable)和不可更改(immutable)對象
在python中,string,tuple,number是不可更改的對象,而list,dict等則是可以修改的對象。
1.不可變類型:變量賦值a = 5後在賦值a = 10,這裏實際是新生成一個int值對象10,在讓a指向它,而5被丟棄,不是改變a的值,相當於新生成了a。
2.可變類型:變量賦值list_a = [1,2,3,4]後在賦值list_a[2] = 5則是將list list_a的第三個元素值更改,本身list_a沒有動,只是其內部的一部分值被修改了。
python函數的參數傳遞:
1.不可變類型:如整數、字符串、元祖。如fun(a),傳遞的只是a的值,沒有影響a對象本身。比如在fun(a)內部修改a的值,只是修改另一個復制的對象,不會影響a本身。
2.可變類型:如列表,字典。如fun(list_a),則是將list_a真正的傳過去,修改後fun外部的list_a也會受影響。
python中一切都是對象,嚴格意義我們不能說值傳遞還是引用傳遞,我們應該說傳不可變對象和傳可變對象。
python傳不可變對象實例:
#!/usr/bin/python #-*- coding:UTF-8 -*- def ChangeInt(a): a = 10 b = 2 ChangeInt(b) print(b) #結果是2
實例中有int對象2,指向它的變量是b,在傳遞給ChangeInt函數時,按傳值的方式復制了變量b,a 和b都指向了同一個int對象,在a = 10時,則新生成一個int值對象10,並讓a指向它。
傳可變對象實例
#!/usr/bin/python #-*- encoding:UTF-8 -*- def ChangeList(mylist): "修改傳入的列表“ mylist.append([1,2,3,4]); print(‘函數內部取值:’,mylist) return #調用Changelist函數 mylist = [10,20,30] ChangeList(mylist) print(‘函數外取值:‘,mylist)
實例中傳入函數的和在末尾添加新內容的對象用的是同一個引用,故輸出結果如下:
函數內取值:[10,20,30,[1,2,3,4]]
函數外取值:[10,20,30,[1,2,3,4]]
實參和形參
形參:定義函數時接收的參數
形參類型:位置參數,動態*args參數,默認參數,動態**kwargs參數
位置參數:位置參數必須以正確的順序傳入函數。調用時的數量必須和聲明時的一樣。
調用test()函數時,你必選傳入一個參數,不然會出現語法錯誤:
#!/usr/bin/python # -*- coding: UTF-8 -*- def test( a ): "打印任何傳入的字符串" print(a); return; #調用test函數 test(); 以上實例輸出結果: Traceback (most recent call last): File "test.py", line 11, in <module> printme(); TypeError: printme() takes exactly 1 argument (0 given)
關鍵字參數:
關鍵字參數和函數調用關系緊密,函數調用使用關鍵字參數來確認傳入的參數值。
使用關鍵字參數允許函數調用時參數的順序與聲明時不一致,因為python解釋器能夠用參數名匹配參數值。
以下實例在函數test()調用時使用參數名:
#!/usr/bin/python #-*- coding:UTF-8 -*- def test(a ,b ): print(a) rerurn print(test(a = 2,b = 2)
默認參數:
調用函數時,默認參數的值如果沒有傳入,則被認為是默認值。下列會打印默認的age,即是沒有傳入age的參數:
#!/usr/bin/python #-*- coding:UTF-8 -*- def test(name,age = 20): print(name,age) return test(age = 22,name = jack) test(name = jack)
動態參數:
你可能需要一個函數能夠處理比當初生命是更多的參數。這些參數叫做不定長參數
語法如下:
def function_name(*args,**kwargs): function_suite return[expression]
加了星號(*)的變量名會存放所有未命名的變量參數。返回為元祖數據類型
加了兩個星號(**)的變量名會存放所有關鍵字參數。返回為字典數據類型
參數定義順序:位置參數->*args->默認參數->**kwargs
實參:函數調用時傳遞的參數
實參類型:位置參數,關鍵字參數
位置參數:必須和函數定義時的參數一對一對應
關鍵字參數:可以通過*[],*()一次性傳遞多個參數給*args;通過**{}一次性傳遞多個參數給**kwargs參數
5.函數的返回值
return語句【表達式】退出函數(結束一個函數的執行),選擇性地向調用方返回一個表達式。
返回值可以是任意數據類型
返回值情況:
1,返回值為None的情況
當不寫return時,默認返回值為None
return不加參數時,返回None
2,返回值不為None的情況
返回一個值: return xxx 返回一個值(一個變量) 任意數據類型
返回多個值: return a,b,[1,2,3] ; 用一個變量接收時返回的是一個元祖,也可以用相應數量的變量去接收
6.變量的作用域
一個程序的所有變量並不是在哪個位置都可以訪問的。訪問權限決定於這個變量實在哪裏賦值的。
命名空間:
局部命名空間
全局命名空間
內置命名空間
定義在函數內部的變量擁有一個局部作用域,定義在函數外的擁有全局作用域。
局部變量只能在其被聲明的函數內部訪問,而全局變量可以在整個程序範圍內訪問。調用函數時,所有在函數內聲明的變量名稱都將被加入到作用域中。如下實例:
#!/usr/bin/python #-*- coding:UTF-8 -*- total = 0 # 這是一個全局變量 def sum(arg1,arg2): ‘‘‘返回2個參數的和‘‘‘ total1 = arg1 + arg2 #total在這裏局部變量 print(‘函數內是局部變量:‘,total) return(total) #調用sum函數 sum(10,20); print(‘函數外是全局變量:’,total) #輸入結果 函數內是局部變量:30 函數外是全局變量:0
變量查找順序:先查找全局作用域,然後內置作用域
global關鍵字:可以是在函數內部聲明的變量變成全局變量
nonlocal關鍵字:可以讓內部函數中的變量在上一層函數中生效,外部必須要有這個變量
#!/usr/bin/python # -*- coding: UTF-8 -*- globvar = 0 def set_globvar_to_one(): global globvar # 使用 global 聲明全局變量 globvar = 1 def print_globvar(): print(globvar) # 沒有使用 global set_globvar_to_one() print globvar # 輸出 1 print_globvar() # 輸出 1,函數內的 globvar 已經是全局變量
7.匿名函數
python使用lambda來創建匿名函數。
1.lambda只是一個表達式,函數體比def簡單很多。
2.lambda的主題式一個表達式,而不是一個代碼塊。僅僅能在lambda表達式中封裝有限的邏輯進去。
3.lambda函數擁有自己的命名空間,且不能訪問只有參數列表之外或全局命名空間裏的參數
4.雖然lambda函數看起來只能寫一行,卻不等同於C或C++的內聯函數,後者的目的是調用小函數時不占用棧內存從而增加運行效率
語法:lambda函數的語法只能包含一個語句,如下:
lambda[arg1[,arg2,......argn]]:expression 如下實例: #!/usr/bin/python #-*- coding:UTF-8 -*- sum = lambda arg1,arg2:arg1 + arg2; print(‘相加後的值為:‘,sum(10,20) print(‘相加後的值為:‘,sum(20,20) 以上實例輸出結果: 相加後的值為:30 相加後的值為:40
8.嵌套函數和閉包
在一個函數內部定義函數就創建了嵌套函數,如下所示:
def outer(): outer_var = ‘outer variable‘ def inner(): return outer_var return innter
在這種類型的函數定義中,函數inner只在函數outer內部有效,所以當內部函數需要被返回(移動到外部作用範圍)或被傳遞給另一個函數時,使用嵌套函數通常比較方便。在如在上面的嵌套函數中,每次調用外部函數時都會創建一個新的嵌套函數實例,這是因為,在每次執行外部函數時,都會執行一次內部函數定義,而其函數體則不會被執行。
嵌套函數可以訪問創建它的環境,這是python函數定義語句的直接結果。一個結果是,外部函數中定義的變量可以在內部函數用引用,即是外部函數已經執行結束。
ef outer(): outer_var = "outer variable" def inner(): return outer_var return inner >>> x = outer() >>> x <function inner at 0x0273BCF0> >>> x() ‘outer variable‘
當內部嵌套的函數引用外部函數中的變量時,我們說嵌套函數相對於引用變量時封閉的。我們可以使用函數對象的一個特殊屬性’_closure_‘來訪問這個封閉的變量,如下所示:
>>>cl = x.__closure__ >>>cl (<cell at 0x029E4470:str object at 0x02A0FD90,) >>>cl[0].cell_contents ‘outer variable‘
python中的閉包有一個古怪的行為。在python2.x以及更低版本中,指向不可變類型(例如字符串和數字)的變量不能再閉包內反彈。
def counter(): count = 0 def c(): count += 1 return count return c >>> c = counter() >>> c() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 4, in c UnboundLocalError: local variable ‘count‘ referenced before assignment
一個相當不可靠的解決方案是,使用一個可變類型來捕獲閉包,如下所示:
def counter(): count = [0] def c(): count[0] += 1 return count[0] return c >>> c = counter() >>> c() 1 >>> c() 2 >>> c() 3
python3引入了nonlocal關鍵字用來解決下面所示的閉包範圍問題。
def counter(): count = 0 def c(): nonlocal count count += 1 return count return c
閉包可以用來維持狀態(與類的作用不同),在一些簡單的情況下,還可以提供一種簡潔性與可讀性比類更強的解決方案
9.裝飾器
裝飾器的本質:是一個閉包函數
裝飾器的功能:在不修改原函數及其調用方式的情況下對原函數功能進行擴展
裝飾器結構:
import time def timer(func): def inner(): start = time.time() func() print(time.time() - start) return inner @timer #==> func1 = timer(func1) def func1(): print(‘in func1‘) func1()
帶參數的裝飾器:
def timer(func): def inner(a): start = time.time() func(a) print(time.time() - start) return inner @timer def func1(a): print(a) func1(1)
帶多個參數的裝飾器:
import time def timer(func): def inner(*args,**kwargs): start = time.time() re = func(*args,**kwargs) print(time.time() - start) return re return inner @timer #==> func1 = timer(func1) def func1(a,b): print(‘in func1‘) @timer #==> func2 = timer(func2) def func2(a): print(‘in func2 and get a:%s‘%(a)) return ‘fun2 over‘ func1(‘aaaaaa‘,‘bbbbbb‘) print(func2(‘aaaaaa‘))
帶返回值的裝飾器:
import time def timer(func): def inner(*args,**kwargs): start = time.time() re = func(*args,**kwargs) print(time.time() - start) return re return inner @timer #==> func2 = timer(func2) def func2(a): print(‘in func2 and get a:%s‘%(a)) return ‘fun2 over‘ func2(‘aaaaaa‘,‘bbbbbb‘) print(func2(‘aaaaaa‘))
多個裝飾器裝飾一個函數:
def wrapper1(func): def inner(): print(‘wrapper1 ,before func‘) func() print(‘wrapper1 ,after func‘) return inner def wrapper2(func): def inner(): print(‘wrapper2 ,before func‘) func() print(‘wrapper2 ,after func‘) return inner @wrapper1 #f = wrapper1(f) ---> wrapper1(wrapper2(f) @wrapper2 #f = wrapper2(f) def f(): print(‘in f‘)
f()
執行結果:
wrapper1 ,before func
wrapper2 ,before func
in f
wrapper2 ,after func
wrapper1 ,after func
帶參數的裝飾器:
F = True #stpe1 裝飾器的開關變量 def outer(flag): #step 2 def wrapper(func): #step 4 def inner(*args,**kwargs): #stpe 6 if flag: #step 9 print(‘before‘) #step 10 ret = func(*args,**kwargs) #step 11 執行原函數 print(‘after‘) #step13 else: ret = func(*args,**kwargs) print(‘123‘) return ret #step 14 return inner #step 7 return wrapper #step 5 @outer(F) #先執行step 3 :outer(True)這個函數,然後step 6:@wrapper #此處把開關參數傳遞給裝飾器函數 def hahaha(): pass #step 12 hahaha() # step 8 相當於inner()
Python函數知識點總結