學習python,從入門到放棄(12)
學習python,從入門到放棄(12)
名稱空間
其實就是存放變數名與變數值繫結關係的地方,大體可分為三類:內建名稱空間、全域性名稱空間、區域性名稱空間。
-
內建名稱空間
屬於python直譯器提前給我們定義好的,像 len() pring() open() 等都是內建名稱空間。程式任意階段任意位置均可使用(全域性有效)。
隨著 python 直譯器執行而產生,隨著 python 直譯器關閉而銷燬。
-
全域性名稱空間
在 py 檔案中編寫的程式碼,執行後產生的變數名、函式名等都會存到全域性名稱空間中。
name = 'jason' # 變數名name存入全域性名稱空間 def index(): # 函式名index存入全域性名稱空間 pass if True: a = 111 # 變數名a存入全域性名稱空間 for i in range(10): # 變數名i存入全域性名稱空間 pass while True: b = 222 # 變數名b存入全域性名稱空間
隨著 py 檔案開始執行而產生,隨著 py 檔案執行結束而銷燬。程式任意階段任意位置均可使用(全域性有效)。
-
區域性名稱空間
函式體程式碼執行產生的都是區域性名稱空間
def index(): name = 'jason' # name存入區域性名稱空間
隨著函式體程式碼開始執行而產生,隨著函式體程式碼執行結束而銷燬。一般情況下只在各自區域性名稱空間中有效(區域性有效)
名字的查詢順序
名稱空間是用來存放名字與值繫結關係的地方,當一行程式碼要使用變數 x 的值時,Python會到所有可用的名稱空間去查詢變數,按照如下順序:
- 區域性名稱空間 - 特指當前函式或類的方法。如果函式定義了一個區域性變數 x,Python 將使用這個變數,然後停止搜尋。
- 全域性名稱空間 - 特指當前的模組。如果模組定義了一個名為 x 的變數,函式或類,Python 將使用這個變數然後停止搜尋。
- 內建名稱空間 - 對每個模組都是全域性的。作為最後的嘗試,Python 將假設 x 是內建函式或變數。
- 如果 Python 在這些名稱空間找不到 x,它將放棄查詢並引發一個 NameError 的異常,同時傳 遞 There is no variable named 'x' 這樣一條資訊。
global 與 nonlocal 關鍵字
-
global 關鍵字
根據 Python 訪問區域性變數和全域性變數的規則:當搜尋一個變數的時候,Python 先從區域性作用域開始搜尋,如果在區域性作用域沒有找到那個變數,那樣 Python 就會像上面的介紹的那樣逐層尋找。最終在全域性變數中找這個變數,如果找不到則丟擲異常。
但有時候會出現,明明已經在全域性變數中找到同名變量了,還是報錯的情況。
因為內部函式有引用外部函式的同名變數或者全域性變數,並且對這個變數有修改的時候,此時 Python 會認為它是一個區域性變數,而函式中並沒有 x 的定義和賦值,所以報錯。
global 關鍵字為解決此問題而生。
x = 111 def a(): print(x) def b(): global x x +=1 print(x) a() # 111 b() # 112
在函式 b 中,顯示地告訴直譯器 x 為全域性變數,然後會在函式外面尋找 x 的定義,執行完 x = x + 1 後,x 依然是全域性變數。
-
nonlocal 關鍵字
nonlocal 關鍵字和 global 關鍵字的作用類似。
但只能用於函式巢狀的情況,也就是函式套函式的情況。
x = 111 def a(): x = 222 def b(): nonlocal x print(x) # 222 x = 333 b() print(x) # 333 a() print(x) # 111
可以從內層修改外層。
函式名的多種用法
-
函式名當變數名賦值
def index(): print('from function index') print(index) # <function index at 0x0000013E6BB11EA0> res = index # 讓res也指向函式體程式碼 print(res) # <function index at 0x0000013E6BB11EA0> index() # from function index res() # from function index
-
函式名當函式的實參
def index(): print('from index') def func(a): print('from func') print(a) # <function index at 0x000001786E6F1EA0> a() # from index func(index) print(index) # <function index at 0x000001786E6F1EA0>
-
函式名當函式的返回值
def func(): print('from func') return index # 將函式名當做返回值 def index(): print('from index') res = func() # res接收函式名 print(res) # 指向的是index函式的記憶體地址 res() # index()
-
函式名作為容器型別的元素
def index(): print('from index') l1 = [11, 22, 33, 44, index] print(l1) l1[-1]() # index()
函式的巢狀
所謂在Python函式中定義巢狀函式,就是說在函式中再定義函式,或者說,把一個函式定義在另一個函式的內部。這是Python語言獨有的一個特點。
函式的巢狀定義,帶來一個好處,就是可以實現用函式去封裝函式。比如有一個函式A,這個A函式在執行過程中,需要呼叫BCDE等好幾個其它的函式,如果BCDE等這些其它的函式,只有A在呼叫,我們就完全可以將BCDE等函式的定義,寫入A函式的內部。這種就封裝了BCED等函式,程式碼看起來更加優雅簡潔!
將BCDE等函式巢狀寫入A函式的內部,還有一個好處,BCDE等函式可以直接訪問A函式區域性空間中的變數。如果BCDE等函式沒有巢狀定義到A函式內部,A在呼叫它們的時候,可能就要傳遞更多的引數給BCDE等函式,BCDE等函式的返回值可能也會變複雜,甚至還可能會增加全域性變數來為他們的互動提供協助。
總結
今天的知識都是偏理論,需要仔細推敲,反覆琢磨,讀懂之後對以後寫程式碼的幫助很大。