Python命名空间和作用域

命名空间 
       是从命名到对象的映射。当前命名空间主要是通过 Python 字典实现的,不过通常不关心具 体的实现方式(除非出于性能考虑),以后也有可能会改变其实现方式。以下有一些命名空间的例 子:内置命名(像 abs() 这样的函数,以及内置异常名)集,模块中的全局命名,函数调用中的局部 命名。某种意义上讲对象的属性集也是一个命名空间。关于命名空间需要了解的一件很重要的事就是 不同命名空间中的命名没有任何联系,例如两个不同的模块可能都会定义一个名为 maximize 的函数而 不会发生混淆-用户必须以模块名为前缀来引用它们。
       顺便提一句,Python 中任何一个“.”之后的命名为 属性 --例如,表达式 z.real 中的 real 是 对象 z 的一个属性。严格来讲,从模块中引用命名是引用属性:表达式 modname.funcname 中, modname 是一个模块对象, funcname 是它的一个属性。因此,模块的属性和模块中的全局命名有 直接的映射关系:它们共享同一命名空间!
       属性可以是只读过或写的。后一种情况下,可以对属性赋值。你可以这样作: modname.the_answer = 42 。可写的属性也可以用 del 语句删除。例如: del modname.the_answer 会从 modname 对象中删除 the_answer 属性。
       不同的命名空间在不同的时刻创建,有不同的生存期。包含内置命名的命名空间在 Python 解释器启动 时创建,会一直保留,不被删除。模块的全局命名空间在模块定义被读入时创建,通常,模块命名空 间也会一直保存到解释器退出。由解释器在最高层调用执行的语句,不管它是从脚本文件中读入还是 来自交互式输入,都是 __main__ 模块的一部分,所以它们也拥有自己的命名空间(内置命名也同样 被包含在一个模块中,它被称作 builtins )。
       当调用函数时,就会为它创建一个局部命名空间,并且在函数返回或抛出一个并没有在函数内部处理 的异常时被删除。(实际上,用遗忘来形容到底发生了什么更为贴切。)当然,每个递归调用都有自 己的局部命名空间。

作用域 
       就是一个 Python 程序可以直接访问命名空间的正文区域。这里的直接访问意思是一个对名称 的错误引用会尝试在命名空间内查找。尽管作用域是静态定义,在使用时他们都是动态的。每次执行 时,至少有三个命名空间可以直接访问的作用域嵌套在一起:
             1  包含局部命名的使用域在最里面,首先被搜索;其次搜索的是中层的作用域,这里包含了同级的函 数;最后搜索最外面的作用域,它包含内置命名。 
             2  首先搜索最内层的作用域,它包含局部命名任意函数包含的作用域,是内层嵌套作用域搜索起点, 包含非局部,但是也非全局的命名 
             3  接下来的作用域包含当前模块的全局命名
             4  最外层的作用域(最后搜索)是包含内置命名的命名空间
       如果一个命名声明为全局的,那么对它的所有引用和赋值会直接搜索包含这个模块全局命名的作用 域。如果要重新绑定最里层作用域之外的变量,可以使用 nonlocal 语句;如果不声明为 nonlocal,这 些变量将是只读的(对这样的变量赋值会在最里面的作用域创建一个新的局部变量,外部具有相同命 名的那个变量不会改变)。
      通常,局部作用域引用当前函数的命名。在函数之外,局部作用域与全局使用域引用同一命名空间: 模块命名空间。类定义也是局部作用域中的另一个命名空间。
重要的是作用域决定于源程序的意义:一个定义于某模块中的函数的全局作用域是该模块的命名空 间,而不是该函数的别名被定义或调用的位置,了解这一点非常重要。另一方面,命名的实际搜索过 程是动态的,在运行时确定的——然而,Python 语言也在不断发展,以后有可能会成为静态的“编 译”时确定,所以不要依赖动态解析!(事实上,局部变量已经是静态确定了。)
       Python 的一个特别之处在于:如果没有使用 global 语法,其赋值操作总是在最里层的作用域。赋值不 会复制数据,只是将命名绑定到对象。删除也是如此: del x 只是从局部作用域的命名空间中删除命 名 x 。事实上,所有引入新命名的操作都作用于局部作用域。特别是 import 语句和函数定义将模块 名或函数绑定于局部作用域(可以使用 global 语句将变量引入到全局作用域)。
      global 语句用以指明某个特定的变量为全局作用域,并重新绑定它。nonlocal 语句用以指明某个特定 的变量为封闭作用域,并重新绑定它
 

你可能感兴趣的:(技术交流,传智播客西安中心)