首页 > 其他学习 > python > python中的命名空间和作用域
2017
10-10

python中的命名空间和作用域

命名空间(namespace)是从命名到对象的映射。Python当前命名空间主要是通过字典实现的,以后有可能会改变其实现方式。某种意义上讲对象的属性集也是一个命名空间。不同命名空间中的命名没有任何联系。

不同的命名空间在不同的时刻创建,有不同的生存期。包含内置命名的命名空间在Python解释器启动时创建,会一直保留,不被删除。模块的全局命名空间在模块定义被读入时创建,通常,模块命名空间也会一直保存到解释器退出。由解释器在最高层调用执行的语句,不管它是从脚本文件中读入还是来自交互式输入,都是 __main__ 模块的一部分,所以它们也拥有自己的命名空间(内置命名也同样被包含在一个模块中,它被称作 builtins )。

当调用函数时,就会为它创建一个局部命名空间,并且在函数返回或抛出一个并没有在函数内部处理的异常时被删除。(实际上,用遗忘来形容到底发生了什么更为贴切。)当然,每个递归调用都有自己的局部命名空间。

作用域(scope)就是一个 Python 程序可以直接访问命名空间的正文区域。这里的直接访问意思是一个对名称的错误引用会尝试在命名空间内查找。尽管作用域是静态定义,在使用时他们都是动态的。每次执行时,至少有三个命名空间可以直接访问的作用域嵌套在一起:

作用域决定于源程序:一个定义于某模块中的函数的全局作用域是该模块的命名空间,而不是该函数的别名被定义或调用的位置,了解这一点非常重要。另一方面,命名的实际搜索过程是动态的,在运行时确定的——然而,Python 语言也在不断发展,以后有可能会成为静态的“编译”时确定,所以不要依赖动态解析!(事实上,局部变量已经是静态确定了。)

如果没有使用global语法,其赋值操作总是在最内层(innermost)的作用域。赋值不会复制数据,只是将命名绑定到对象。删除也只是从局部作用域的命名空间中删除命名x。事实上,所有引入新命名的操作都作用于局部作用域。特别是import语句和函数定义将模块名或函数绑定于局部作用域(可以使用global语句将变量引入到全局作用域)。

如果一个命名声明为全局的,那么对它的所有引用和赋值会直接搜索包含这个模块全局命名的作用域。如果要重新绑定最里层作用域之外的变量,可以使用 nonlocal 语句;如果不声明为 nonlocal,这些变量将是只读的(对这样的变量赋值会在最里面的作用域创建一个新的局部变量,外部具有相同命名的那个变量不会改变)。

global 语句用以指明某个特定的变量为全局作用域,并重新绑定它。nonlocal 语句用以指明某个特定的变量为封闭作用域,并重新绑定它。

LEGB-rule

在一个Python程序运行中,至少有4个scopes是存在的。直接访问一个变量可能在这四个namespace中逐一搜索。

Local(innermost):包含局部变量。比如一个函数/方法内部。

Enclosing:包含了非局部(non-local)也非全局(non-global)的变量。如同级函数

Global(next-to-last):当前脚本的最外层。

Built-in(outtermost):Python __builtin__ 模块。包含了内建的变量/关键字等。

”LEGB-rule”,即scope的搜索顺序:Local -> Enclosing -> Global -> Built-in

当有一个变量在 local 域中找不到时,Python会找上一层的作用域,即 enclosing 域(该域不一定存在)。enclosing 域还找不到的时候,再往上一层,搜索模块内的 global 域。最后,会在 built-in 域中搜索。对于最终没有搜索到时,Python会抛出一个 NameError 异常。

作用域可以嵌套。比如模块导入时。

下面会有一个UnboundLocalError报错,表示局部变量在赋值前就被引用的错误:

def outer():

b = 1

def inner():

print (b)

#b += 1

b = 4

inner()

outer()

Python解释器执行到inner()中的print(b)时,首先发现有个变量b在当前作用域(local)中无法找到,然后继续尝试把整块代码解释完,在后面的语句中找到了b。那么b是属于inner()作用域的。既然对变量b的赋值(声明)发生在 print 语句之后,print语句执行时变量b是还未被声明的,于是抛出错误:变量在赋值前就被引用。

在这个例子中,b += 1语句也会导致同样的结果。因为 b += 1 等同于 b = b + 1。

最后编辑:
作者:qingheluo
这个作者貌似有点懒,什么都没有留下。