Python名稱空間和作用域

在本節中,我們將來學習Python名稱空間和命名的作用域。

Python中的命名:

Python中的命名是賦予物件的識別符號。 Python是一種物件導向的程式語言,這意味著它所有東西都是Python中的一個物件,其中命名名稱用來訪問具體的物件。

例如,當你給一個變數x = 3賦值時, 這裡3是一個物件並儲存在一個記憶體位置(RAM)中。 這個記憶體位置是一個被命名的記憶體位置,可以通過名字x訪問。 該物件3的地址可以通過使用內建函式id()來獲得。

>>> x = 3
>>> print('id(3) =', id(3))
id(3) = 1864160336
>>> print('id(x) =', id(x))
id(x) = 1864160336

現在這裡的物件3儲存在一個名字為x的位置中,因此它們的記憶體地址是相同的。

當你將x的值賦給某個其他變數時,比如說y, 並改變x的值,那麼x將會有一個新的位置,y將會有前一個x的位置。 如下所示:

x = 3
print('id(x) =', id(x))
x = 4
print('id(4) =', id(4))
print('id(x) =', id(x))
y = 3
print('id(y) =', id(y))
id(x) = 1864160336
id(4) = 1864160352
id(x) = 1864160352
id(y) = 1864160336

你可以看得出,y的記憶體地址等於x的舊記憶體地址。

Pythhon中的名稱空間:

Python名稱空間是命名名稱的集合。 名稱空間是名稱到物件的對映,在Python中它的資料型別是一個字典。 名稱空間確保程式中使用的每個名稱都是唯一的。

名稱空間在直譯器啟動時建立,當程式執行結束時刪除。 該名稱空間已經包含所有內建名稱,因此,無論何時需要內建函式(例如id()),都可以直接在程式中使用它。

當你呼叫一個函式時,會建立一個包含所有已定義名稱的本地名稱空間。

Python名稱空間,可以分為三種型別:

  1. 本地名稱空間 - 在某個函式或者類方法裡面的本地名稱集合。
  2. 全域性名稱空間 - 在當前模組下的命名集合
  3. 內建名稱空間 - Python內建命名集合

下面我們來舉幾個例子,來具體說明下它們的含義。

Python名稱空間-本地名稱空間

>>> def localTest(arg):
	param = 2
	print(locals())
	
>>> localTest(1)
{'param': 2, 'arg': 1}

locals()就是我們上面說的本地名稱空間,它是一個Python字典物件。其中,鍵是命名,裡面也包括了輸入引數,值是具體命名所對應的資料。

思考?

假如函式中既沒有輸入引數,也沒有本地區域性變數,那它的本地名稱空間是什麼呢?

自己來試試吧。

Python名稱空間-全域性名稱空間

NameSpace_GlobalNameSpcae.py
x = 1
y = 2
stringX = "String X"

def globalTest():
    for (key, value) in globals().items():
        print("{} - {}".format(key, value))
    
globalTest()
__name__ - __main__
__doc__ - None
__package__ - None
__loader__ - <_frozen_importlib_external.SourceFileLoader object at 0x0000020146FED630>
__spec__ - None
__annotations__ - {}
__builtins__ - <module 'builtins' (built-in)>
__file__ - NameSpace_GlobalNameSpcae.py
__cached__ - None
x - 1
y - 2
stringX - String X
globalTest - <function globalTest at 0x0000020146F91E18>

從結果我們可以看出,全域性名稱空間裡包括了整個模組內的命名名稱,比如變數xystringX,函式名globalTest,而且還包括了一些內建的變數命名,比如__name__, __file__等等。

Python中變數作用域:

在程式中建立變數時,你可能無法從程式的每個地方都能訪問該變數, 這是因為變數的作用域的存在。 你試著訪問名稱空間中未定義的變數時候,就會得到系統報錯UnboundLocalError:local variable referenced before assignment

作用域可以被定義為你可以在沒有任何字首的情況下訪問你的名稱空間的這樣的一個域或者範圍。

作用域可以分類為:

  1. L - 區域性作用域Scope of a function where you have local names.
  2. E - enclosing scope,閉包函式作用域,也就是在巢狀函式中的作用域Scope of a module where you have global variables.
  3. G - 全域性作用域
  4. B - 內建作用域

當在函式中引用一個變數的時候,以上的作用域順序也是Python搜尋的一個順序L->E-G-B,首先嚐試區域性作用域,沒找到的話,繼續搜尋閉包函式作用域,然後再是全域性作用域和內建作用域。

接下來,我們用一個例子來說明Python變數作用域的細節。

VariableScope_SearchOrder.py
outer = 'global variable'

def searchOrderFunc():
	enclosing = 'enclosing variable'
	
	def searchOrderFuncInner():
		inner = 'inner variable'
		print(inner)           #fetch from (L)ocal scope
		print(enclosing)       #fetch from (E)nclosing scope
		print(outer)           #fetch from (G)lobal scope
		print(any)             #fetch from (B)uilt-ins
	
	searchOrderFuncInner()
    
searchOrderFunc()
inner variable
enclosing variable
global variable
<built-in function any>