『無為則無心』Python函式 — 31、名稱空間(namespace)

繁華似錦Fighting發表於2022-01-06

1、什麼是名稱空間

名稱空間指的是變數儲存的位置,每一個變數都需要儲存到指定的名稱空間當中。

全域性名稱空間用來儲存全域性變數,函式名稱空間用來儲存函式中的變數。也就是說每一個作用域都會有一個它對應的名稱空間,全域性作用域就會有一個全域性的名稱空間,函式作用域就會有一個函式的名稱空間。

名稱空間實際上就是一個字典,是一個專門用來儲存變數的字典。

名稱空間提供了在專案中避免名字衝突的一種方法。各個名稱空間是獨立的,沒有任何關係的,所以一個名稱空間中不能有重名,但不同的名稱空間是可以重名而沒有任何影響。

我們舉一個計算機系統中的例子,一個資料夾(目錄)中可以包含多個資料夾,每個資料夾中不能有相同的檔名,但不同資料夾中的檔案可以重名。

image

2、三種名稱空間

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

如下圖所示:

image

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()

總結:我們只要知道有名稱空間這個概念就行,實際上就是個字典,我們開發的時候一般不會修改名稱空間的。

相關文章