Python 全局空间与局部空间:命名空间、变量作用域及 LEGB 原则详解
本文深入解析 Python 中的全局空间与局部空间概念,详细阐述内建、全局及局部三种命名空间的创建与销毁顺序。通过对比全局变量与局部变量的作用域与生命周期,说明 global 和 nonlocal 关键字在修改变量时的具体行为。重点解读 LEGB 变量查找原则,并结合 globals() 和 locals() 函数的使用示例,帮助开发者清晰理解变量可见性及嵌套函数中的变量访问机制。
一、空间和局部空间
1、命名空间
引入命名空间的概念旨在界定变量的可见范围及其生命周期;该概念所覆盖的区域即被称为作用域。系统通过类似字典的结构划分区域来存储所有数据,建立变量名与具体值之间的映射关系。Python 中主要包含三种类型的命名空间。
内建命名空间: 在解释器启动时自动生成,直至解释器完全关闭才销毁,拥有最长的生存周期; 全局命名空间: 在模块文件开始运行时创建,直到解释器运行结束才销毁,生存周期次之; 局部命名空间: 仅在函数被调用时生成,内部局部变量随之创建,函数调用结束后立即释放,生存周期最短; 创建和销毁顺序 创建顺序: Python 解释器启动 -> 创建内建命名空间 -> 创建全局命名空间 -> 创建局部命名空间 销毁顺序: 函数调用结束后 -> 销毁函数对应的局部命名空间数据 -> 销毁全局命名空间数据 -> 销毁内建命名空间数据
2、全局变量和局部变量
什么是全局和局部变量:
局部变量是指在函数内部定义的变量,它们位于局部命名空间中,其可见范围仅限于函数内部,即只能在函数代码块内被使用。
# 在函数中创建的变量就是局部变量
def func():
var = '局部变量'
# 局部变量不可以在非对应局部环境中使用
print(var) # error, 该变量不存在全局变量是指在函数外部定义的变量,或者通过 global 关键字在函数内部显式声明的变量。全局变量位于全局命名空间中,其作用域覆盖整个文件,意味着在整个文件的任意位置均可访问该全局变量。
# 在全局环境中创建的变量就是全局变量
var = '全局变量'
def func():
# 在局部中也可以使用全局变量
print(var) # 全局变量
func()建议避免局部变量与全局变量同名。若两者同名,在局部作用域内将无法直接访问同名的全局变量,因为局部变量会遮蔽全局变量。
var = '全局变量'
def func():
# 先使用了全局变量
print(var) # error, 找不到该变量
# 然后局部变量和全局变量同名,那么新的局部变量就会在局部空间中覆盖了全局变量的一切影响力,这就叫做局部变量修改了全局变量;
# 这样的话导致在局部空间中无法在使用该全局变量,之前在局部空间中使用的该变量就成为了先调用后定义;导致出错。
var = '局部变量'
print(var)
func()
# 但是局部同名变量不会影响到全局变量的值
print(var) # 全局变量内置函数属于内建命名空间范畴,指的是 Python 解释器自带提供的函数集合。
3、作用域
局部变量作用域:局限于函数内部 全局变量作用域:覆盖整个文件
4、生命周期
内置变量 -> 全局变量 -> 局部变量 内置变量的生命周期从 Python 程序启动时开始,直到程序彻底结束才会被释放; 全局变量的生命周期从创建时刻开始,直至程序结束或被显式清除才会释放; 局部变量的生命周期从创建时刻开始,直到所在局部空间执行完毕或被清除即告释放;
5、全局部函数和关键字的使用
函数

globals()
返回当前全局作用域内的所有内容。
若在全局代码块中调用 globals,获取的是调用前已存在的所有变量,返回一个字典对象,反映全局空间的作用域状态;
# 定义一些全局变量
a, b, c = 1, 2, 3
# 调用globals函数
res = globals()
# 第一次打印,包含a b c
print(res)
'''
结果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000002DBDCA5D198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'res': {...}}
'''
# 再定义一些变量
d, e, f = 1, 2, 3
# 第二次打印,包含a b c d e f
print(res)
'''
结果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000002DBDCA5D198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'res': {...}, 'd': 1, 'e': 2, 'f': 3}
'''
若在局部函数内部调用 globals,获取的是调用时刻之前的所有全局变量,返回字典对象,同样反映全局空间的作用域;
# 定义一些全局变量
a, b, c = 1, 2, 3
# 在局部环境中使用globals函数
def func():
res = globals()
print(res)
# 调用函数
func()
'''
结果:不包含 d e f
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001E7C287D198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'func': <function func at 0x000001E7C2772F28>}
'''
# 再定义一些全局变量
d, e, f = 4, 5, 6
# 第二次调用函数
func()
'''
结果:包含 d e f
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000021A3F3DD198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'func': <function func at 0x0000021A3F2D2F28>, 'd': 4, 'e': 5, 'f': 6}
'''globals 函数可用于动态创建全局变量
dic = globals()
print(dic) # 返回系统的字典
'''
结果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000026F357ED198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'dic': {...}}
'''
# 在全局的字典当中,通过添加键值对,自动创建全局变量,对应的键是变量名,对应的值是变量指向的值
dic['msr123123123'] = '123456'
print(msr123123123) # 123456
# 查看全局内容
print(dic)
'''
结果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000161D944D198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'dic': {...}, 'msr123123123': '123456'}
'''
locals()
返回当前所在作用域内的所有内容。 若在全局代码块中调用 locals 之后,获取的是调用前已存在的所有变量,返回字典对象,反映全局空间的作用域;
# 定义一些全局变量
a, b, c = 1, 2, 3
# 调用locals函数
res = locals()
# 第一次打印,包含a b c
print(res)
'''
结果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000018C82A3D198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test1.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'res': {...}}
'''
# 再定义一些变量
d, e, f = 1, 2, 3
# 第二次打印,包含a b c d e f
print(res)
'''
结果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000018C82A3D198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test1.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'res': {...}, 'd': 1, 'e': 2, 'f': 3}
'''
若在局部函数内部调用 locals 之后,获取的是调用时刻之前的所有局部变量,返回字典对象,反映局部空间的作用域;
# 定义一些局部变量
def func():
# 局部变量
aa, bb, cc = 11, 22, 33
# 第一遍调用
res = locals()
# 第一次打印,包含 aa bb cc
print(res) # {'cc': 33, 'bb': 22, 'aa': 11}
# 再定义一些局部变量
dd, ee, ff = 44, 55, 66
# 第二次打印,不包含 dd ee ff
print(res) # {'cc': 33, 'bb': 22, 'aa': 11}
# 调用第二遍
res2 = locals()
# 打印第一次的调用,包含 dd ee ff
print(res) # {'cc': 33, 'bb': 22, 'aa': 11, 'ff': 66, 'ee': 55, 'dd': 44, 'res': {...}}
# 打印第二次的调用,包含 dd ee ff
print(res2) # {'cc': 33, 'bb': 22, 'aa': 11, 'ff': 66, 'ee': 55, 'dd': 44, 'res': {...}}
# 调用函数,返回在函数中的局部变量
func()关键字

global
在局部环境中定义的变量默认为局部变量,在全局环境中不可见。但若使用 global 关键字声明,则该变量变为全局变量,可在整个全局环境中使用。
def func():
var = '局部变量'
global glvar
glvar = '全局变量'
# 一定要执行局部环境哟
func()
# 全局环境中
print(var) # error,局部变量不能调用
# 使用global定义的变量是全局变量
print(glvar) # 全局变量在局部环境中默认无法直接修改全局变量的值,使用 global 关键字可以在局部环境中修改全局变量的值。
var = '全局变量'
def func():
global var
var = '局部环境中修改'
func()
print(var) # 局部环境中修改6、函数的嵌套
在深入理解 nonlocal 之前,需要先掌握关于函数嵌套的基础知识。
内函数和外函数
函数之间支持相互嵌套,外层调用的称为外函数,被包裹在内的称为内函数。
def outer():
print('我叫outer,是外函数')
def inner():
print('我叫inner,在outer的里面,是内函数')
# 在外函数中执行内函数
inner()
# 执行外函数
outer()
'''
结果:
我叫outer,是外函数
我叫inner,在outer的里面,是内函数
'''- 内函数不能直接在外函数之外执行调用
- 即使调用了外函数,内函数也不可以在函数外部被直接调用
- 内函数仅可以在外函数的代码块内部被调用
- 内函数在外函数内部调用时,存在严格的先后顺序,必须先定义后调用。这是因为 Python 没有预读机制,这一特性适用于 Python 中的所有代码场景。
# 外层是outer,内层是inner,最里层是smaller,调用smaller里的所有代码
def outer():
print('我叫outer,是最外层函数,是inner和smaller的外函数')
def inner():
print('我叫inner,是outer的内函数,是smaller的外函数')
def smaller():
print('我叫smaller,是outer和inner的内函数')
# 先在inner中执行smaller
smaller()
# 然后在outer中执行inner
inner()
# 最后再执行outer才能执行smaller函数
outer()
'''
结果:
我叫outer,是最外层函数,是inner和smaller的外函数
我叫inner,是outer的内函数,是smaller的外函数
我叫smaller,是outer和inner的内函数
'''在多层函数嵌套时需注意,无论外函数还是内函数,本质上都是函数,因此函数内部定义的变量均为局部变量。 内函数可以访问外函数的局部变量,但外函数无法直接使用内函数定义的局部变量。
二、LEGB 原则
LEGB 原则是一种就近查找变量的规则,依据该原则,变量查找顺序是从下往上、从里向外依次进行。
B————Builtin(Python):Python 内置模块的命名空间 (内建作用域) G————Global(module):函数外部所在的命名空间 (全局作用域) E————Enclosing Function Locals:外部嵌套函数的作用域(嵌套作用域) L————Local(Function):当前函数内的作用域 (局部作用域)

nonlocal
现在正式学习 nonlocal 关键字,nonlocal 的作用是修改当前局部环境中上一层的局部变量。根据此作用可知,nonlocal 的使用环境至少涉及两级嵌套,且外层局部环境中必须存在一个同名的局部变量。
def outer():
# 定义变量
lvar = 'outer var'
def inner():
# 内函数使用nonlocal修改上一层的局部变量
nonlocal lvar
lvar = 'inner var'
# 执行inner函数
inner()
print(lvar)
outer() # inner var假如上一层的局部环境中没有这个变量怎么办,那么就根据 LEGB 原则向上寻找。
def outer():
# 定义变量
lvar = 'outer var'
def inner():
def smaller():
# smaller中修改变量,但是inner中没有,就向上寻找修改outer中的变量
nonlocal lvar
lvar = 'smaller var'
# 执行 smaller函数
smaller()
# 执行inner函数
inner()
print(lvar)
# 执行outer函数
outer()如果层层寻找,直到最外层的函数中也没有这个变量,那么就会报错,因为 nonlocal 只会修改局部变量,如果超出范围,就会报错。
var = 1 # 变量在最外层的函数之外,也就是全局变量,nonlocal无法修改
def outer():
def inner():
def smaller():
nonlocal var # error,没有局部变量
var = 2
print(var)
smaller()
inner()
outer()
三、总结
全局变量和局部变量
局部环境中可以调用全局变量,但是不能修改(但是如果全局变量是可变数据则可以修改其中的值) 全局环境中不能调用局部变量 也不能修改
函数 global() (在函数内部使用,可以对全局变量进行操作)
- 1、可以在局部环境中定义全局变量
- 2、可以在局部环境中修改全局变量
nonlocal() (在内函数中使用,可以在内函数中修改外函数中的局部变量)
关键字:
locals 1、locals 获取当前作用域当中所有的变量 如果在全局调用 locals 之后,获取的是打印之前的所有变量,返回字典,全局作用域 如果在局部调用 locals 之后,获取的是调用之前的所有变量,返回字典,局部作用域
globals 2、globals 只获取全局空间中的所有变量 如果在全局调用 globals 之后,获取的是打印之前的所用变量,返回字典,全局作用域 如果在局部调用 globals 之后,获取的是调用之前的所用变量,返回字典,全局作用域
到此这篇关于Python 全局空间和局部空间的文章就介绍到这了,更多相关Python命名空间内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









