函數是把一些語句集合在一塊兒的程序結構,用於把複雜的流程細分紅不一樣的組件,可以減小代碼的冗餘、代碼的複用和修改代碼的代價。html
函數能夠0個、1個或多個參數,向函數傳遞參數,能夠控制函數的流程。函數還能夠返回代碼執行的結果,從技術上講,任何函數都要返回結果,一個沒有返回值的函數會自動返回none對象。若是調用者須要函數返回結果,須要顯式使用return語句。編程
Python使用def 語句將建立一個函數對象,並將其賦值給一個變量名,()內是函數的參數,參數經過賦值向參數傳值。app
def fun_name (arg1,age2...): fun_body
return語句表示函數調用的結束,並把結果傳遞給調用者。return語句是可選的,若是它沒有出現,那麼函數將會在控制流執行完函數主體時結束。函數
1,def是可執行的語句測試
def語句是實時執行的,不只def語句,Python中的全部語句都是實時運行的,並無獨立的編譯時間。def語句是一個可執行的語句,在def執行前,函數並不存在,直到def語句執行以後,函數才被建立。ui
2,函數是一個對象,函數名是變量spa
def語句是一個賦值語句,函數是一個對象,函數名是一個變量,def語句設置函數名和函數對象的引用。code
當def語句運行的時候,它建立了一個新的函數對象,並將其賦值給一個變量名。htm
3,參數是經過賦值傳遞的對象
Python經過賦值(=)把參數傳遞給函數,這和普通的賦值語句(a=1,或a=b)的行爲是相同。當傳遞常量給參數時,參數引用的是一個全新的對象;當傳遞變量給參數,參數和變量是對象的共享引用。
4,函數是能夠嵌套的
一個def是一個語句,能夠出如今任一語句能夠出現的地方,甚至嵌套在其餘的語句中。這就是說,函數內部能夠嵌套函數的定義,例如:
def times(x,y): z=x*y def print_result(): print(z) print_result()
函數 print_result()是一個嵌入函數,定義在函數times(x,y)以內。
實際上,Python的函數是有層次結構,最外層的def是頂層函數,在頂層函數內部定義的函數是嵌套函數。
函數經過表達式調用,傳入一些值,並返回結果。函數調用的格式是:函數名 + (args),小括號中是傳遞給參數的變量或值,例如:
func_name(var1,var2...)
若是函數存在返回值,使用變量來接收函數的返回值:
ret_value=fun_name(var1,var2...)
在調用函數時,函數的行爲依賴於類型,這是由於函數是語句的集合,語句包含操做符,而操做符的行爲是依賴於類型的,
例如,函數times返回兩個參數的乘積,當傳入數字時,函數 times(2,4) 返回8,* 的做用是計算乘積;當傳入字符類型時,函數 times('ab',2) 返回'abab',*號的做用是重複字符串。換句話說,函數times()的做用取決於傳遞給它的值。
def times(x,y): return x *y
調用函數時,這種依賴於類型的行爲稱爲多態,就是說,一個操做的做用取決於操做對象的類型。函數的多態性,使得函數能夠自動適用於全部類別的對象類型。
若是傳給函數的對象有預期的方法和表達式操做符,那麼函數就兼容對象。若是傳遞的對象不支持預期的接口,Python會在 * 表達式運行時檢測到錯誤,並自動拋出一個異常。
這種特性,使得Python代碼不該該關心特定的類型,函數應該爲對象編寫接口,而不是數據類型。固然,這種多態的編程模型意味着:必須測試代碼去檢測執行結果是否錯誤,而不是編寫代碼進行類型檢查。
在Python代碼中變量無處不在,命名空間就是保存變量名的地方,變量名可以訪問(可見)的命名空間叫作做用域。
當在程序中使用變量名時,Python建立、改變或者查找變量都是在命名空間中進行的,變量名被賦值的位置決定了變量名可以被訪問的範圍。
1,變量的分類
Python中的變量在第一次被賦值時建立,而且必須通過賦值後才能使用。因爲沒有變量的聲明,Python把變量名被賦值的地點關聯爲(綁定爲)一個特定的命名空間。
根據變量的命名空間,把變量大體分爲三類:
2,變量的做用域
變量的做用域是指變量可見的範圍,一個變量的做用域老是由變量被賦值的地方決定的,也就是說,變量被賦值的地方決定了變量可見的範圍。
在默認狀況下,一個函數的全部變量名都是與函數的命名空間相關聯的:
因爲變量能夠在三個地方分配,那麼變量的做用域實際上分爲三類:
3,做用域法則
全部變量名均可以概括爲內置的(builtin)、全局的(global)和本地的(local)。
內置的模塊是Python預先定義好,能夠直接引用的。
模塊定義的是全局做用域,全局做用域的做用範圍僅限於單個模塊(文件),也就是說,在一個文件的頂層的變量名對於這個文件內部的代碼而言是全局的。
在默認狀況下,在函數內部,賦值的變量名除非聲明爲全局變量或非本地變量以外,都是本地做用域內的。函數還定義了嵌套的做用域,使其內部使用的變量名本地化,以便函數內部使用的變量名不會與函數外的變量名衝突。每次對函數的調用都會建立一個新的本地做用域。若是須要給一個嵌套的def中的變量名賦值,從Python 3.0開始,可使用 nonlocal語句聲明來作到。
注意:模塊頂層的函數名是全局變量,函數內部的def定義的是局部變量;函數的參數是本地變量;一個函數內部的任何類型的賦值都會把一個變量劃定爲本地的,這意味着,函數內部的賦值(=)語句,def語句等,定義的都是本地變量。
4,變量名解析(LEGB原則)
變量名的解析聽從LEGB原則,當引用一個變量時,Python按照如下順序依次進行查找:從本地變量中、在任意上層函數的做用域、在全局做用域,最後在內置做用域中查找。
LEGB法則解析變量名的詳細機制:
把嵌套做用域定義爲:在當前的def語句以外,在頂層def語句以內的做用域,嵌套做用域的解析細節:
5,在函數內引用全局變量
global不是聲明一個類型,而是聲明命名的命名空間是全局的,也就是說,告訴函數打算聲明一個或多個全局變量名。
對於全局變量名,這裏對用法做一個總結:
例如,x是全局變量,在函數func中使用global 聲明x是全局變量,對x賦值,就是修改全局變量的值:
x=11 def func(): global x x=12
使用global語句把變量聲明爲全局變量,這樣,在函數內部就能夠修改全局變量的值,也就是說,global語句容許在def中修改全局變量的值。
global語句包含了關鍵字global,其後跟着一個或多個由逗號分開的變量名,當在函數內被賦值或引用時,全部列出來的變量都被映射到全局變量名。
global x,y,z
6,在函數內引用上層的非本地變量
Pytho 3.0 引入了nonlocal語句,用於在一個函數內聲明一個非本地的變量,該變量定義於一個def語句中,而且位於嵌套做用域的上層。
例如,函數foo1定義了變量var1和var2,要想在函數foo2中改變它們的值,必須在foo2中使用nonlocal語句把它們聲明爲非本地變量:
def foo1: var1=1 var2=2 ... def foo2: nonlocal var1,var2,..
nonlocal語句是一個聲明語句,用於把函數內的變量聲明爲非本地變量。非本地變量是指不在本函數內定義的,而是在上層函數中定義的本地變量。
nonlocal語句的用法解析:
nonlocal語句提供了一種方式,使得嵌套的函數可以提供可寫的狀態信息,以便在隨後調用嵌套的函數時,可以記住這些信息。簡而言之,nonlocal語句的引入使得Python容許修改非本地變量。
Python的閉合函數是指一個可以記住嵌套做用域的變量值的函數,儘管那個做用域已經不存在了。
例如,建立一個閉合函數maker,該函數生成並返回一個嵌套函數action,卻並調用這個內嵌的函數。
def maker(x): def action(y): return x*y return action
調用閉合函數,獲得的是生成的內嵌函數的一個引用。當咱們調用閉合函數,它會返回內嵌函數的引用;當調用內嵌函數action時,咱們發現儘管閉合函數已經返回並退出,可是,內嵌函數記住了閉合函數內部的變量x的值。
f=maker(2) f(3)
也就是說,閉合函數的本地做用域的信息被保留了下來。爲了可以在內嵌的def中使用變量x的值,Python自動記住了所須要的上層做用域的任意值。
注意:若是lambda或者def在函數中定義,嵌套在一個循環之中,而且嵌套的函數引用了一個上層做用域的變量,該變量被循環所改變,全部在這個循環中產生的函數將會由相同的值——在最後一次循環中完成時被引用變量的值。
>>> def maker(): ... acts=[] ... for i in range(5): ... acts.append(lambda x:i**x) ... return acts ... >>> acts=maker() >>> acts[0](2) 16
由於嵌套做用域中的變量在嵌套的函數被調用時才進行檢查,因此,它們實際上記住的是一樣的值(在最後一次循環迭代中循環變量的值)。
也就是說,只有當調用acts[0](2)時,採起檢查變量i的值,此時變i的值是最後一次迭代的值4。要解決這類問題,必須在函數maker調用時,對i的值進行評估,並保存起來。
>>> def maker(): ... acts=[] ... for i in range(5): ... acts.append(lambda x, i=i : i**x) ... return acts
爲了讓這類代碼可以工做,必須使用默認參數把當前的值傳遞給嵌套做用域的變量。由於默認參數是在嵌套函數建立時評估的(而不是其稍後調用時),因此,每個函數都記住了本身的變量 i 的值。
參考文檔:
原文出處:https://www.cnblogs.com/ljhdo/p/10104834.html