Python 中的命名空間
1. 命名空間的定義
命名空間 (Namespace) 是從名稱到值的映射,大部分的命名空間都是通過(guò) Python 字典來(lái)實(shí)現(xiàn)的,它的鍵就是變量名,它的值是變量的值。
1.1 例子
一個(gè)包含 3 個(gè)變量的命名空間,如下圖所示:

圖: 定義了 3 個(gè)變量的命名空間
- 第一個(gè)變量
- 名為 a,值為 1
- 第二個(gè)變量
- 名為 b,值為 2
- 第三個(gè)變量
- 名為 c,值為 3
1.2 在同一個(gè)命名空間中,不允許重名
在同一個(gè)命名空間中,每個(gè)變量的名稱是唯一的,不允許重名。在下圖中,嘗試定義 2 個(gè)同名變量:

- 命名空間中存在變量 b,取值為 2
- 命名空間中存在變量 b,取值為 3
- 因?yàn)樘幱谕粋€(gè)命名空間,這種情況是不允許的
1.3 在不同的命名空間中,允許重名
在下圖中,存在兩個(gè)不同的命名空間:命名空間 A 和命名空間 B。

- 在命名空間 A 中,有 3 個(gè)變量 a、b、c,取值分別是 1、2、3
- 在命名空間 B 中,有 3 個(gè)變量 a、b、c,取值分別是 11、22、33
- 因?yàn)樘幱诓煌拿臻g,這種情況是允許的
2. 三種命名空間
Python 中存在有三種命名空間:
- 內(nèi)置命名空間:記錄了 Python 的內(nèi)置函數(shù)
- 全局命名空間:記錄了模塊級(jí)別的變量
- 局部命名空間:記錄了函數(shù)的參數(shù)和局部變量
2.1 內(nèi)置命名空間
Python 解釋器內(nèi)置了很多函數(shù), 不需要使用 import 導(dǎo)入即可使用,例如:
>>> max(1, 2)
2
>>> abs(-123)
123
- 函數(shù) max 計(jì)算最大值
- 函數(shù) abs 計(jì)算絕對(duì)值
- Python 程序可以直接使用這兩個(gè)內(nèi)置函數(shù)
Python 提供了一個(gè)內(nèi)置命名空間,用于記錄這些內(nèi)置函數(shù)。Python 中存在一個(gè)特殊的 builtins 模塊,它記錄了所有的內(nèi)置函數(shù),示例如下:
>>> import builtins
>>> dir(builtins)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ZeroDivisionError', 'abs', 'all', 'any','ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
>>>
- 在第 1 行,導(dǎo)入 builtins 模塊
- 在第 2 行,使用 dir 列出 builtins 模塊中的變量和函數(shù)的名稱
>>> m = builtins.max
>>> m(1, 2)
2
>>> a = builtins.abs
>>> a(-123)
123
- 在第 1 行,引用 builtins 命名空間中的 max 函數(shù)
- 在第 4 行,引用 builtins 命名空間中的 abs 函數(shù)
2.2 全局命名空間
在 Python 的全局命名空間中,記錄了模塊級(jí)別的變量,包括變量、函數(shù)、類。
Python 中的內(nèi)置函數(shù) globals() 返回表示全局命名空間的字典,示例如下:
class Person:
def __init__(self, name):
self.name = name
def show(person):
print(person.name)
tom = Person('tom')
jerry = Person('jerry')
dict = globals()
print(dict)
- 在第 1 行,在全局空間定義了類 Person
- 在第 5 行,在全局空間定義了函數(shù) show
- 在第 8 行,在全局空間定義了實(shí)例變量 tom
- 在第 9 行,在全局空間定義了實(shí)例變量 jerry
程序輸出如下:
{
'__name__': '__main__',
'__doc__': None,
'__package__': None,
'__file__': 'globals.py',
'__cached__': None,
'Person': <class '__main__.Person'>,
'show': <function show at 0x0000000001D03E18>,
'tom': <__main__.Person object at 0x0000000001E1BC50>,
'jerry': <__main__.Person object at 0x0000000001E1BCC0>,
}
輸出包括了 Person、show、tom 和 jerry,它們是用戶定義的全局函數(shù)和變量。
2.3 局部命名空間
在 Python 的局部命名空間中,記錄了函數(shù)的參數(shù)和局部變量。
Python 中的內(nèi)置函數(shù) locals() 返回表示局部命名空間的字典,示例如下:
def function(a, b):
c = 3
d = 4
dict = locals()
print(dict)
function(1, 2)
- 在第 1 行,函數(shù) function 定義了參數(shù) a 和 b
- 在第 2 行,函數(shù) function 定義了局部變量 c
- 在第 3 行,函數(shù) function 定義了局部變量 d
程序輸出如下:
{'a':1, 'b':2, 'c':3, 'd':4}
輸出包括了 a、b、c 和 d,它們是函數(shù)的參數(shù)和局部變量。
3. 命名空間的查找順序
Python 程序訪問(wèn)變量時(shí),按照如下規(guī)則查找變量:
- 在局部命名空間中,查找變量
- 如果找不到,則在全局命名空間中,查找變量
- 如果找不到,則在內(nèi)置命名空間中,查找變量
- 如果找不到,則拋出 NameError 異常
下面的例子演示了查找順序:
a = 1
b = 2
def function(c, d):
e = 5
f = 6
訪問(wèn)某個(gè)變量
function(3, 4)
-
程序包含了 3 個(gè)命名空間
- 內(nèi)置命名空間,包括: max、min、abs 等內(nèi)置函數(shù)
- 全局命名空間,包括:a、b、function
- 局部命名空間,包括:c、d、e、f
-
在第 7 行,訪問(wèn)某個(gè)變量
- 如果訪問(wèn)的變量是 c,則能在局部命名空間中找到
- 如果訪問(wèn)的變量是 a,則能在全部命名空間中找到
- 如果訪問(wèn)的變量是 max,則能在內(nèi)置命名空間中找到
- 如果訪問(wèn)的變量是 x,在以上三個(gè)命名空間中查找不到,拋出異常 NameError