作用域

Posted koala-king

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了作用域相关的知识,希望对你有一定的参考价值。

Python作用域基础

当你在一个程序中使用变量名时,Python创建,改变或查找变量名都是在所谓的命名空间(一个保存变量的地方)中进行的。也就是说,在代码中变量名被赋值的位置决定了这个变量名能被访问到的位置。

关于所有变量名,包括作用域的定义在内,都是在Python赋值的时候生成的。正如我们所知,Python中的变量名在第一次赋值的时候已经创建,并且必须经过赋值后才能使用。由于变量名最初没有声明,Python将一个变量名被赋值的地点关联为一个特定的命名空间。换句话说,在代码中给一个变量赋值的地方决定了这个变量将存在于哪个命名空间,也就是它可见的范围。

 

在默认的情况下,一个函数的所有变量名都是与函数的命名空间相关联的,这意味着:

1·一个在def内定义的变量名能够被def内的代码使用。不能在函数的外部引用这样的变量名。

2·一个在def内定义的变量名能够被def内的代码使用。不能再函数的外部引用这样的变量名。

3·def之中的变量名与def之外的变量名并不冲突,即使是使用在别处的相同的变量名。一个在def之外被赋值(例如,在另一个def之中或者在模块文件的顶层)的变量x与这个def之中的赋值的变量x是完全不同的变量

 

在任何情况下,一个变量的作用域(它所使用的地方)总是由代码中被赋值的地方所决定,并且与函数调用完全没有关系。变量可以在3个不同的地方分配,分别对应3个不同的作用域:

1·如果一个变量在def内赋值,它被定为在这个函数内

2·如果一个变量在一个嵌套的def中赋值,对于嵌套的函数来说,它是非本地的

3·如果在def之外赋值,它就是整个文件全局的。

函数的作用域有助于防止程序中变量名的冲突,并且有助于函数成为更加独立的程序单元。

 

作用域法则

函数提供了嵌套的命名空间(作用域),使其内部使用的变量名本地化,以便函数内部使用的变量名不会与函数外(在一个模块或是其他函数中)的变量名产生冲突。需要注意的是:函数定义了本地的作用域(local),而模块定义的是全局作用域(global)这两个作用域的关系是这样的:

1·内嵌的模块是全局作用域

每个模块都是一个全局作用域(也就是说,一个创建于模块文件顶层的变量的命名空间)。对于外部的全局变量就成为一个模块对象的属性,但是在一个模块中能够像简单的变量一样使用

2·全局作用域的作用范围仅限于单个文件

这里的全局指的是在一个文件的顶层的变量名仅对于这个文件内部的代码而言是全局的。在Python中是没有基于一个单个的、无所不包的情景文件的全局作用域的。替代这种方法的是,变量名由模块文件隔开,并且必须精确的导入一个模块文件才能够使用这个文件夹中定义的变量名。当你在Python中听到”全局的“,你就应该想到”模块“。

3·每次对函数的调用都创建了一个新的本地作用域

每次调用函数,都创建了一个新的本地作用域。也就是说,将会由那个函数创建的变量的命名空间。可以认为每一个def语句(以及lambda表达式)都定义了一个新的本地作用域,但是因为Python允许函数在循环中调用自身(递归),所以从技术上讲,本地作用域实际上的对应的是函数的调用。换句话说,每一个函数调用都创建了一个本地命名空间。递归在处理不能提前预知的流程结构时是一个有用的工具。

4·赋值的变量名除非声明为全局变量或非本地变量,否则均为本地变量

在默认的情况下,所有函数定义内部的变量名是位于本地作用域(与函数调用相关的)内的如果需要给一个在函数内部却位于模块文件顶层的变量名赋值,需要在函数内部通过global来进行声明。如果需要给位于一个嵌套的def中的名称赋值,可以通过一条nonlocal语句声明它来做到。

5·所有的其他变量名都可以归纳为本地、全局、内置的

在函数内部的尚未赋值的变量名是一个在一定范围内(在这个def内)的本地变量

全局(在一个模块的命名空间内部)

内置(由Python的预定义__builtin__模块提供的)

变量。

 

这里还要注意的是:交互命令提示模式输入的代码也遵从这些规则。交互模式运行的代码实际上真的输入到一个叫做__main__的内置模块中,这个模块就像是一个模块文件一样工作,但是,结果随着输入而反馈。因此,交互模式也在一个模块中创建名称,并由此遵守常规的作用域规则:它们杜宇交互绘画来说是全局的。

还要注意的是,一个函数内部的任何类型的赋值都会把一个名称划定为本地的。这包括:=语句、import中的模块名称、def中的函数名称、函数参数名称等。如果在一个def中以任何方式赋值一个名称,它都将对于该函数成为本地的

原处改变对象也不会把变量变成本地变量,实际上只有对变量名赋值才可以。在函数内部的像L.append(X)这样的语句并不会将L划分为本地变量,而L = X却可以。通常记住名称和对象之间的清楚的区分是有帮助的:修改一个对象并不是一个名称赋值。

以上是关于作用域的主要内容,如果未能解决你的问题,请参考以下文章

0140 JavaScript作用域:概述全局作用域函数作用域块级作用域

作用域和闭包作用域和作用域链

js 静态作用域和动态作用域

JavaScript 作用域作用域链变量提升

JavaScript 作用域作用域链变量提升

js 函数作用域, 块级作用域和词法作用域