Python变量作用域详解:局部与全局变量的区别及遮蔽处理
本文深入解析Python中的变量作用域机制,区分局部变量与全局变量的定义及内存生命周期。详细讲解如何使用globals()和locals()函数查看变量字典,并重点阐述局部变量遮蔽全局变量的原理。通过代码示例演示如何利用global关键字或globals()字典解决变量访问冲突,确保代码逻辑清晰可控。
Python变量作用域基础概念
在编写程序时,每个变量都有其特定的有效范围,这一范围被称为变量的作用域。
依据变量定义的具体位置,变量主要被划分为两类:
- 局部变量:指在函数内部定义的变量,这其中包括了函数的形参。
- 全局变量:指在函数外部、整个模块或全局范围内定义的变量。
局部变量与全局变量的内存机制
每当一个函数开始执行,系统会为其分配一块临时的内存空间,所有在该函数中定义的局部变量均存储于此。一旦函数执行完毕,这块内存空间随即被释放,导致其中的局部变量失效。因此,在函数外部无法直接访问这些局部变量。
全局变量则具有更广泛的可见性,它们可以在程序内的任意函数中被访问。
无论是在局部还是全局范围内,变量都“持有”着特定的值。从数据结构的角度看,这些作用域及其包含的变量与值类似于一个“隐形的字典”,其中变量名充当字典的键(key),而变量值则对应字典的值(value)。
获取变量字典的工具函数
Python 提供了三个内置工具函数,用于获取指定作用域内的“变量字典”:
globals():该函数返回包含当前全局作用域内所有变量的字典。
locals():该函数返回当前局部作用域内所有变量的字典。
vars(object):用于获取指定对象范围内的变量字典。若未传入 object 参数,vars() 的行为与 locals() 完全一致。
尽管 globals() 和 locals() 在表面上看似功能迥异,但二者存在紧密的联系,主要体现为以下两点:
locals() 始终返回当前所在局部作用域的变量字典。因此,若在函数外部(即全局作用域)调用 locals(),其结果等同于获取全局变量字典;而 globals() 无论在任何位置执行,始终返回全局变量字典。
通常建议仅通过 globals() 和 locals() 获取的“变量字典”进行读取操作,避免修改。然而实际上,修改 globals() 返回的全局变量字典会直接改变全局变量的值;相比之下,修改 locals() 返回的局部变量字典则不会影响实际的局部变量值。
locals与globals函数的实际应用
以下程序演示了如何利用 locals() 和 globals() 函数来访问局部和全局范围内的“变量字典”:
def test ():
age = 20
# 直接访问age局部变量
print(age) # 输出20
# 访问函数局部范围的“变量数组”
print(locals()) # {'age': 20}
# 通过函数局部范围的“变量数组”访问age变量
print(locals()['age']) # 20
# 通过locals函数局部范围的“变量数组”改变age变量的值
locals()['age'] = 12
# 再次访问age变量的值
print('xxx', age) # 依然输出20
# 通过globals函数修改x全局变量
globals()['x'] = 19
x = 5
y = 20
print(globals()) # {..., 'x': 5, 'y': 20}
# 在全局访问内使用locals函数,访问的是全局变量的“变量数组”
print(locals()) # {..., 'x': 5, 'y': 20}
# 直接访问x全局变量
print(x) # 5
# 通过全局变量的“变量数组”访问x全局变量
print(globals()['x']) # 5
# 通过全局变量的“变量数组”对x全局变量赋值
globals()['x'] = 39
print(x) # 输出39
# 在全局范围内使用locals函数对x全局变量赋值
locals()['x'] = 99
print(x) # 输出99
通过上述程序可以明确,locals() 用于访问特定作用域内的所有变量字典,而 globals() 则专门用于访问全局范围内的全局变量字典。
局部变量遮蔽全局变量的处理方案
虽然全局变量默认可在所有函数中访问,但若在函数内部定义了与全局变量同名的变量,就会发生局部变量遮蔽(hide)全局变量的现象。例如以下程序:
name = 'Charlie'
def test ():
# 直接访问name全局变量
print(name) # Charlie
test()
print(name)
在上述程序中,第 4 行直接访问 name 变量是合法的,程序将输出 Charlie。若在此后增加如下代码行:
name = '孙悟空'
再次运行该程序,将出现如下错误提示:
UnboundLocalError : local variable ‘name' referenced before assignment
该错误表明粗体字代码所引用的 name 变量尚未定义。造成这一现象的原因是,在 test() 函数中增加了“name='孙悟空'”这一赋值语句。
根据 Python 语法规则,在函数内部对未定义的变量进行赋值时,默认行为是重新定义一个新的局部变量。因此,上述代码实际上重新定义了 name 局部变量,导致原有的 name 全局变量被遮蔽,从而引发报错。
为解决此问题,可采用以下两种修改策略:
访问被遮蔽的全局变量。若希望程序仍能访问 name 全局变量,同时允许在函数内重新定义 name 局部变量,可通过 globals() 函数实现。修改后的程序如下:
name = 'Charlie'
def test ():
# 直接访问name全局变量
print(globals()['name']) # Charlie
name = '孙悟空'
test()
print(name) # Charlie
在函数中声明全局变量。若要在函数中对全局变量进行赋值(而非重新定义局部变量),可使用 global 语句显式声明。修改后的程序如下:
name = 'Charlie'
def test ():
# 声明name是全局变量,后面的赋值语句不会重新定义局部变量
global name
# 直接访问name全局变量
print(name) # Charlie
name = '孙悟空'
test()
print(name) # 孙悟空
添加“global name”声明后,程序会将 name 视为全局变量。这意味着 test() 函数中对 name 的赋值操作是对全局变量的修改,而非创建新的局部变量。
Python变量作用域层级扩展
知识点扩展:
python3 之 变量作用域
作用域:指命名空间中可直接访问的 Python 程序文本区域。这里的‘可直接访问’意味着:对名称的引用(非限定),会尝试在命名空间中查找该名称;
- L:local,局部作用域,即在函数内部定义的变量;
- E:enclosing,嵌套的父级函数的局部作用域,即包含当前函数的上级函数的局部作用域,但不包括全局作用域;
- G:globa,全局变量,即在模块级别定义的变量;
- B:built-in,内建作用域,指系统固定模块中的变量,例如:int,bytearray等
到此这篇关于什么是Python变量作用域的文章就介绍到这了,更多相关Python变量作用域详解内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













