Python 命名空间

Python 命名空间

1. 命名空间的定义

命名空间 (Namespace) 是从名称到值的映射,大部分的命名空间都是通过 Python 字典来实现的,它的键就是变量名,它的值是变量的值。

1.1 例子

一个包含 3 个变量的命名空间,如下图所示:

图: 定义了 3 个变量的命名空间

  • 第一个变量

    • 名为 a,值为 1

  • 第二个变量

    • 名为 b,值为 2

  • 第三个变量

    • 名为 c,值为 3

1.2 在同一个命名空间中,不允许重名

在同一个命名空间中,每个变量的名称是唯一的,不允许重名。在下图中,尝试定义 2 个同名变量:

图: 在同一个命名空间中,不允许重名

  • 命名空间中存在变量 b,取值为 2

  • 命名空间中存在变量 b,取值为 3

  • 因为处于同一个命名空间,这种情况是不允许的

1.3 在不同的命名空间中,允许重名

在下图中,存在两个不同的命名空间:命名空间 A 和命名空间 B。

图: 在不同的命名空间中,允许重名

  • 在命名空间 A 中,有 3 个变量 a、b、c,取值分别是 1、2、3

  • 在命名空间 B 中,有 3 个变量 a、b、c,取值分别是 11、22、33

  • 因为处于不同的命名空间,这种情况是允许的

2. 三种命名空间

Python 中存在有三种命名空间:

  • 内置命名空间:记录了 Python 的内置函数

  • 全局命名空间:记录了模块级别的变量

  • 局部命名空间:记录了函数的参数和局部变量

2.1 内置命名空间

Python 解释器内置了很多函数, 不需要使用 import 导入即可使用,例如:

>>> max(, )>>> abs(-)
  • 函数 max 计算最大值

  • 函数 abs 计算绝对值

  • Python 程序可以直接使用这两个内置函数

Python 提供了一个内置命名空间,用于记录这些内置函数。Python 中存在一个特殊的 builtins 模块,它记录了所有的内置函数,示例如下:

>>> 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 行,导入 builtins 模块

  • 在第 2 行,使用 dir 列出 builtins 模块中的变量和函数的名称

>>> m = builtins.max>>> m(, )>>> a = builtins.abs>>> a(-)
  • 在第 1 行,引用 builtins 命名空间中的 max 函数

  • 在第 4 行,引用 builtins 命名空间中的 abs 函数

2.2 全局命名空间

在 Python 的全局命名空间中,记录了模块级别的变量,包括变量、函数、类。

Python 中的内置函数 globals() 返回表示全局命名空间的字典,示例如下:

class Person:def __init__(self, name):self.name = namedef show(person):print(person.name)tom = Person('tom') jerry = Person('jerry')dict = globals()print(dict)
  • 在第 1 行,在全局空间定义了类 Person

  • 在第 5 行,在全局空间定义了函数 show

  • 在第 8 行,在全局空间定义了实例变量 tom

  • 在第 9 行,在全局空间定义了实例变量 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,它们是用户定义的全局函数和变量。

2.3 局部命名空间

在 Python 的局部命名空间中,记录了函数的参数和局部变量。

Python 中的内置函数 locals() 返回表示局部命名空间的字典,示例如下:

def function(a, b):c = 
    d = dict = locals()print(dict)function(, )
  • 在第 1 行,函数 function 定义了参数 a 和 b

  • 在第 2 行,函数 function 定义了局部变量 c

  • 在第 3 行,函数 function 定义了局部变量 d

程序输出如下:

{'a':1, 'b':2, 'c':3, 'd':4}

输出包括了 a、b、c 和 d,它们是函数的参数和局部变量。

3. 命名空间的查找顺序

Python 程序访问变量时,按照如下规则查找变量:

  1. 在局部命名空间中,查找变量

  2. 如果找不到,则在全局命名空间中,查找变量

  3. 如果找不到,则在内置命名空间中,查找变量

  4. 如果找不到,则抛出 NameError 异常

下面的例子演示了查找顺序:

a = b = def function(c, d):e = 
    f = 
    访问某个变量

function(, )
  • 程序包含了 3 个命名空间

    • 内置命名空间,包括: max、min、abs 等内置函数

    • 全局命名空间,包括:a、b、function

    • 局部命名空间,包括:c、d、e、f

  • 在第 7 行,访问某个变量

    • 如果访问的变量是 c,则能在局部命名空间中找到

    • 如果访问的变量是 a,则能在全部命名空间中找到

    • 如果访问的变量是 max,则能在内置命名空间中找到

    • 如果访问的变量是 x,在以上三个命名空间中查找不到,抛出异常 NameError