Python全局变量与局部变量详解:作用域、LEGB规则及global/nonlocal用法
本文深入解析Python中全局变量与局部变量的区别,详细阐述LEGB(Local, Enclosing, Global, Built-in)变量查找顺序。通过代码示例演示global和nonlocal关键字如何修改嵌套作用域中的变量,并系统介绍全局、局部及内置命名空间的加载与取值机制,帮助开发者避免变量引用错误。
本文旨在通过图解方式,清晰阐述Python中全局变量与局部变量的核心概念。文中结合具体示例代码进行详细解析,内容详实,对读者的学习或实际工作具有显著的参考价值,建议相关读者仔细阅读并参考。
Python变量作用域基础
在深入探讨全局变量和局部变量之前,有必要先厘清“作用域”这一基础概念,它是理解变量可见性的关键。
a = 10
def func():
b = 20
def inner():
c = 30
以下面的程序片段为例,我们将尝试打印变量a、b和c的值。

运行结果显示,只有变量a成功打印出值10,而变量b和c均引发报错。这一现象直观地体现了作用域对变量访问的限制。
我们可以将新创建的.py文件视为一个独立的模块。在该模块层级定义的变量(如示例中的a)被称为全局变量,其作用范围覆盖整个模块,因此在模块内的任何位置均可被调用。
相比之下,变量b和c定义在函数内部,这类变量被称为局部变量。局部变量的作用域被严格限制在定义它的函数内部,函数外部无法直接访问。

接下来,我们进一步探讨一个更复杂的问题。
函数func及其内部嵌套的函数inner,是否有权调用变量a?
此外,函数func本身能否调用变量c?
答案是肯定的:由于a是定义在模块层级的全局变量,它可以在程序的任何地方被调用。

然而,函数func无法直接调用变量c。这是因为如果我们将func视为一个整体作用域,那么inner则是定义在func内部的嵌套函数,而c仅仅是inner函数内部的局部变量,其可见性不向func的其他部分或外部暴露。

总结而言,定义在全局作用域的变量可以在任何地方被调用;而定义在函数内部的局部变量,仅能在该函数内部使用。
LEGB变量查找顺序
Python中变量的查找遵循特定的顺序,即LEGB规则。
该规则定义的查找优先级为:局部作用域(Local)> 外层嵌套作用域(Enclosing)> 当前模块的全局作用域(Global)> Python内置作用域(Built-in)。
global与nonlocal关键字详解
接下来,我们将介绍两个用于处理全局和局部变量关系的关键字:global和nonlocal。
直接通过代码示例进行说明。

我们可以看到,如果在局部作用域中定义了变量a,直接尝试在局部作用域外调用它将会报错。
只有当变量在定义之后被调用时,才能正常打印其值。需要注意的是,这种局部定义不会改变全局变量a的原始值。

如果希望在局部名称空间中修改全局变量a的值,应当如何处理?这时就需要使用global关键字。

执行结果可见,全局变量a的值已被成功修改为15。
下面来讲解nonlocal关键字的用法。

在上述示例中,尝试打印变量a和b时出现错误,报错提示指出变量b未定义。
变量a之所以没有报错,是因为它是全局变量,存在且可访问;而变量b是局部变量,在当前作用域未声明,因此报错。修正方法如下。

由于b是定义在嵌套函数内部的局部变量,在调用前需使用nonlocal关键字进行声明,声明后即可正常调用并修改其值。
Python名称空间机制
为了更深入理解变量机制,我们需要了解“名称空间”的概念。
名称空间主要分为以下几类。
全局命名空间(Global):在模块加载执行时创建,记录了模块中定义的所有变量,包括函数、类、导入的模块以及模块级的变量和常量。
局部命名空间(Local):每个函数拥有独立的命名空间,记录该函数中定义的所有变量,包括函数参数和函数内部定义的局部变量。
内置命名空间(Built-in):所有模块均可访问,包含Python内置的函数和异常类型(例如:input、print、str、list、tuple等)。
名称空间的加载顺序如下。
加载顺序为:内置命名空间(程序运行前加载) > 全局命名空间(程序运行中,从上到下逐步加载) > 局部命名空间(程序运行中,仅在函数调用时加载)。
名称空间的取值(查找)顺序如下。
在局部作用域调用变量时:查找顺序为局部命名空间 > 全局命名空间 > 内置命名空间。
在全局作用域调用变量时:查找顺序为全局命名空间 > 内置命名空间。
综上所述,Python在寻找变量时,遵循从小范围到大范围的层级查找策略,依次在各个名称空间中进行搜索。
以上就是本文的全部内容,希望这些解析能对各位的学习有所帮助,也欢迎大家继续支持本站,获取更多技术资讯。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









