1. 程式人生 > 其它 >python-名稱空間和作用域

python-名稱空間和作用域

技術標籤:pythonpython

名稱空間(Namespace)是從名稱到物件的對映,大部分的名稱空間都是通過 Python 字典來實現的。
名稱空間的作用:程式在 直接訪問 變數時,會在當前的名稱空間內查詢。

1.名稱空間的定義

名稱空間通常是一個字典,其中key是物件名,而value是物件。

  • 內建名稱空間(built-in names)
    Python 語言內建的名稱,比如函式名 abs、char 和異常名稱 BaseException、Exception 等等。
  • 全域性名稱空間(global names)
    模組中定義的名稱,記錄了模組的變數,包括函式、類、其它匯入的模組、模組級的變數和常量。
  • 區域性名稱空間(local names)
    函式中定義的名稱,記錄了函式的變數,包括函式的引數和區域性定義的變數。(類中定義的也是)

2.名稱空間的查詢順序

當一行程式碼要使用變數 x 的值時,Python 會到所有可用的名字空間去查詢變數,按照如下順序:
1、區域性名稱空間:特指當前函式或類的方法。如果函式定義了一個區域性變數 x,或一個引數 x,Python 將使用它,然後停止搜尋。
2、全域性名稱空間:特指當前的模組。如果模組定義了一個名為 x 的變數,函式或類,Python 將使用它然後停止搜尋。
3、內建名稱空間:對每個模組都是全域性的。作為最後的嘗試,Python 將假設 x 是內建函式或變數。

4、如果 Python 在這些名字空間找不到 x,它將放棄查詢並引發一個 NameError 異常,如,NameError: name ‘aa’ is not defined。

  • 巢狀函式的情況:
    1、先在當前 (巢狀的或 lambda) 函式的名稱空間中搜索
    2、然後是在父函式的名稱空間中搜索
    3、接著是模組名稱空間中搜索
    4、最後在內建名稱空間中搜索

3.名稱空間的生命週期

名稱空間的生命週期取決於物件的作用域,如果物件執行完成,則該名稱空間的生命週期就結束。
因此,我們無法從外部名稱空間訪問內部名稱空間的物件。

不同的名稱空間在不同的時刻建立,有不同的生存期。

1、內建名稱空間在 Python 直譯器啟動時建立,會一直保留,不被刪除。

2、模組的全域性名稱空間在模組定義被讀入時建立,通常模組名稱空間也會一直儲存到直譯器退出。
3、當函式被呼叫時建立一個區域性名稱空間,當函式返回結果 或 丟擲異常時,被刪除。每一個遞迴呼叫的函式都擁有自己的名稱空間

4、名稱空間的訪問

locals():訪問區域性名稱空間,只讀。

locals()僅是區域性名稱空間的代理當再次呼叫 locals() 時,由於重新採集,則動態修改的內容會被丟棄

globals():訪問全域性名稱空間,可讀寫。

globals 返回實際的全域性名字空間,對 globals 所返回的 dict 的任何的改動都會直接影響到全域性變數

5.作用域

作用域就是一個 Python 程式可以直接訪問名稱空間正文區域

g_count = 0  # 全域性作用域
def outer():
    o_count = 1  # 閉包函式外的函式中
    def inner():
        i_count = 2  # 區域性作用域

內建作用域是通過一個名為 builtin 的標準模組來實現的,但是這個變數名自身並沒有放入內建作用域內,所以必須匯入這個檔案才能夠使用它。在Python3.0中,可以使用以下的程式碼來檢視到底預定義了哪些變數:

>>> import builtins
>>> dir(builtins)

在一個 python 程式中,直接訪問一個變數,會從內到外依次訪問所有的作用域直到找到,否則會報未定義的錯誤。
變數訪問方式:

a = 1
class A:
    def func(self): pass
print(a) # 直接訪問:不加點的訪問
print(A.func) # 屬性訪問:加點的訪問
  • 四種作用域:

L(Local):最內層,包含區域性變數,比如一個函式/方法內部。
E(Enclosing):包含了非區域性(non-local)也非全域性(non-global)的變數。比如兩個巢狀函式,一個函式(或類) A 裡面又包含了一個函式 B ,那麼對於 B 中的名稱來說 A 中的作用域就為 nonlocal。
G(Global):當前指令碼的最外層,比如當前模組的全域性變數。
B(Built-in): 包含了內建的變數/關鍵字等。,最後被搜尋

LEGB:先在區域性作用域查詢,再在閉包中查詢,接著在全域性中查詢,最後在內建作用域查詢。

  • 注意

Python 中只有模組(module),類(class)以及函式(def、lambda)才會引入新的作用域,其它的程式碼塊(如 if/elif/ese/、try/except、for/while等)是不會引入新的作用域的,也就是說這些語句內定義的變數,外部也可以訪問