1、什麼是名稱空間
名稱空間指的是變數儲存的位置,每一個變數都需要儲存到指定的名稱空間當中。
全域性名稱空間用來儲存全域性變數,函式名稱空間用來儲存函式中的變數。也就是說每一個作用域都會有一個它對應的名稱空間,全域性作用域就會有一個全域性的名稱空間,函式作用域就會有一個函式的名稱空間。
名稱空間實際上就是一個字典,是一個專門用來儲存變數的字典。
名稱空間提供了在專案中避免名字衝突的一種方法。各個名稱空間是獨立的,沒有任何關係的,所以一個名稱空間中不能有重名,但不同的名稱空間是可以重名而沒有任何影響。
我們舉一個計算機系統中的例子,一個資料夾(目錄)中可以包含多個資料夾,每個資料夾中不能有相同的檔名,但不同資料夾中的檔案可以重名。
2、三種名稱空間
- 內建名稱(
built-in names
), Python語言內建的名稱,比如函式名abs
、char
和異常名稱BaseException
、Exception
等等。 - 全域性名稱(
global names
),模組中定義的名稱,記錄了模組的變數,包括函式、類、其它匯入的模組、模組級的變數和常量。 - 區域性名稱(
local names
),函式中定義的名稱,記錄了函式的變數,包括函式的引數和區域性定義的變數。(類中定義的也是)
如下圖所示:
3、名稱空間查詢順序
假設我們要使用變數runoob
,則Python的查詢順序為:區域性的名稱空間 -> 全域性名稱空間 -> 內建名稱空間。
如果找不到變數runoob
,它將放棄查詢並引發一個NameError
異常:NameError: name 'runoob' is not defined
。
4、名稱空間的生命週期
名稱空間的生命週期取決於物件的作用域,如果物件執行完成,則該名稱空間的生命週期就結束。
因此,我們無法從外部名稱空間訪問內部名稱空間的物件。
5、如何獲取當前的名稱空間
locals()
函式用來獲取當前作用域的名稱空間。
也就是如果在全域性作用域中呼叫locals()
函式,則獲取全域性名稱空間,如果在函式作用域中呼叫locals()
函式則獲取函式名稱空間,最終返回的是一個字典。
示例如下:
c = 10
def fn(a):
# 在函式中對形參進行重新賦值,不會影響其他的變數
a = 20
print('a =', a, id(a))
# 當前名稱空間
scope = locals()
# 列印名稱空間
print(scope)
# 檢視locals()函式返回的物件型別
print(type(scope))
"""
輸出結果;
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000000025222C8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:/PyCharmWorkspace/hello-python-01/firstpythonfile.py', '__cached__': None, 'c': 10, 'fn4': <function fn4 at 0x0000000002575798>, 'scope': {...}}
<class 'dict'>
"""
我們可以看到名稱空間就是一個字典,我們在程式中定義的全域性變數c
也可以在返回的字典中檢視到。
# 那其實列印全域性變數c就有兩種方式
scope = locals()
print("c =", c) # c = 10
print("c =", scope['c']) # c = 10
同理,向名稱空間的字典中新增key-value
,就相當於在全域性中建立了一個變數,但一般不建議這麼做。
# NameError: name 'f' is not defined
print("f =", f)
# 向名稱空間中新增一個key-value
scope = locals()
scope['f'] = 1000
print("f =", f) # f = 1000
全域性和函式內部的名稱空間同理。
全域性作用域的地方是不能獲取到函式作用域中名稱空間的資訊的。但是函式作用域中可以使用globals()
函式,獲取全域性名稱空間的資訊。
def fn():
global_scope = globals()
總結:我們只要知道有名稱空間這個概念就行,實際上就是個字典,我們開發的時候一般不會修改名稱空間的。