名字空间和模块
(参考教材的9.2节)

一个"名字空间"(name space)就是从名字到其与其相关的值(对象)的一个映射,这是程序执行中的一个概念。 名字空间的例子如:

  • Python 所有内置名字集合(包含所有内置函数等),约束到相应内置对象;
  • 一个模块里的所有全局名字及其约束;
  • 一个函数调用中的函数里的局部名字及其约束;
  • 后面讨论类时考虑的一个对象的属性也可以看作一个名字空间。
注意:不同的名字空间里的名字相互间毫无关系,即使同名也一样毫无关系。

名字空间和属性引用

名字空间有可能嵌套。例如在解释器状态下执行 “import math” 导入模块 math,名字 math 就会约束到装入的模块对象,用名字 math 将找到该模块。math 模块内部的名字及其定义形成了另一个名字空间,可以用 math 加圆点的方式进入该名字空间,引用其中的名字。如 math.sin 等等。

下面将把写在圆点之后的名字称为属性,一个模块的属性与这个模块的全局名一一对应。从模块名出发访问该模块里的属性用圆点记法,例如 math.sin(…)。

一个名字空间里的属性可以是只读的,也可以是可写的。可写属性可以进行赋值,还可以用标准函数 del 删除。

对于模块而言,其名字空间里的所有名字都是可写的。

名字空间的创建和撤销

每个(每种)名字空间有具有特定的创建时间:
  1. 包含所有内置名的名字空间在 Python 解释器启动时创建,一直存在到 Python 系统终止;
  2. 模块的全局名字空间在该模块定义读入时创建,存在到系统终止;
  3. 由顶层 Python 解释器执行的语句(无论来自读入的脚本文件或交互式输入),都当作名字为 __main__ 的模块里的语句,在该模块的名字空间里执行;
  4. 函数的局部名字空间在函数调用时创建,函数终止时(无论是由于 return 或发生异常而终止)撤销。函数的每个递归调用将建立一个自己的名字空间。
与名字空间相关的重要概念是前面讨论过的作用域。一个作用域是 Python 程序里的一段代码正文,其中的名字可以在相应的名字空间里直接访问。虽然作用域是根据程序正文静态确定的,但它的作用却是动态。程序执行进入一个作用域时建立相应的名字空间。

程序执行过程中,直接出现的名字(没有圆点符号的名字)表示直接访问,按下面顺序检查当时的名字空间:

  1. 最内层名字空间,其中包含了所有的局部名字;
  2. 可能存在的外围函数的名字空间,从内向外逐层检索。这个(这些)名字空间里出现的是那些既非局部也且非全局的名字;
  3. 当前模块的全局名字空间,其中包含当前模块的全局名字;
  4. 最外层名字空间,其中包含所有的内置函数。
如果一个名字已经声明为 global,就直接到当前模块的全局名字空间去找它;如果一个名字声明为 nonlocal,就直接到局部名字空间之外的其他名字空间去找。如果没有上面两种声明而该名字最终确定为非局部的,它就作为只读名。如果找不到就是名字错误。

在执行一个函数的过程中,局部名字是这个函数的局部空间里的名字;如果执行处于所有函数之外,所谓的局部名字也就是执行所在的模块里的全局名字。

注意:作用域是静态确定的。例如,在一个模块里定义了一个函数,无论这个函数在哪里调用,其全局作用域永远都是定义这个函数的模块的全局名字空间,与调用的位置无关。

对于没有 global 也没有 nonlocal 声明的名字:

  • 赋值操作总是在最内层名字空间进行,在最内层名字空间创建这个名字的约束,或者修改名字的约束值;
  • del 总是删除最内层名字空间里的名字约束;
  • 函数定义在最内层名字空间建立新函数名和函数对象的约束;
  • import 语句把模块名(与模块对象的约束)或模块里的定义引入最内层名字空间。
本页及相关页面(除另声明者外)由裘宗燕创建维护,可自由用于各种学习活动。其他使用需得到作者许可。