精简解答python命名空间和作用域
文章目录
- 精简解答python命名空间和作用域
- 1.命名空间
- 2.变量在命名空间的存在形式
- 3.命名空间查找顺序
- 4.命名空间的生命周期
- 5.命名空间的实例
1.命名空间
简单来说,命名空间就是变量的作用域。在python中,命名空间(变量作用域)主要有三类:
- 局部命名空间:特指当前函数或类的方法。如果函数定义了一个局部变量 x,或一个参数 x,Python 将使用它,然后停止搜索。
- 全局命名空间:特指当前的模块。如果模块定义了一个名为 x 的变量,函数或类,Python 将使用它然后停止搜索。
- 内置命名空间:对每个模块都是全局的。作为最后的尝试,Python 将假设 x 是内置函数或变量。
注意:牢记一句话:只有函数、类、模块会产生作用域,代码块不会产生作用域
2.变量在命名空间的存在形式
命名空间是一个字典的实现,键为变量名,值是变量对应的值。各个命名空间是独立没有关系的,一个命名空间中不能有重名,但是不同的命名空间可以重名而没有任何影响。
3.命名空间查找顺序
当一行代码要使用变量 x 的值时,Python 会到所有可用的名字空间去查找变量,他会按照从小到大的顺序去找:局部命名空间->全局命名空间->内置命名空间,如果找到则会停止搜索。
4.命名空间的生命周期
- 内置命名空间在 Python 解释器启动时创建,会一直保留,不被删除。
- 模块的全局命名空间在模块定义被读入时创建,通常模块命名空间也会一直保存到解释器退出。
- 当函数被调用时创建一个局部命名空间,当函数返回结果 或 抛出异常时,被删除。每一个递归调用的函数都拥有自己的命名空间。
5.命名空间的实例
(1)代码块不会产生作用域
if True:
i = 1
print(i)
# 结果:1
解释:这里代码块不会产生作用域,所以,i是存在于全局命名空间{i: 1}
,print是位于全局空间内的代码,所以,print能找到i
再举一个例子,加深理解
def f():
i = 1
if i == 1:
vol = 0
else:
vol = -1
print(vol)
f()
# 结果:
0
(2)函数的作用域
def f():
i = 1
f()
print(i)
# 结果:
NameError: name 'i' is not defined
这个例子很容易理解,不做说明
(3)创建命名空间时,python会先检查到要被赋值的代码并填充局部命名空间
i = 1
def f():
i += 1
print(i)
f()
# 结果:
local variable 'i' referenced before assignment
解释:由于创建命名空间时,python会检查代码并填充局部命名空间。在python运行那行代码之前,就发现了对i的赋值,并把它添加到局部命名空间中,即{i: None}
。当函数执行时,python解释器认为i在局部命名空间中但没有值,所以会产生错误。
再举一个例子加深理解:
i = 1
def f():
i
print(i)
f()
# 结果:
1
解释:因为函数f()中没有赋值语句,所以,该局部空间内没有键值对,当执行到语句i
时,因为局部命名空间里没有,所以会到全局命名空间中去找,结果找到键值对i: 1
(4)多重函数嵌套,嵌套的内部函数又是一个局部作用域.
def g():
i += 1
print(i)
def f():
i = 2
g()
f()
# 结果:
name 'i' is not defined
解释:错误原因和(3)中一样
再举一个例子加深印象:
def g():
i = 1
print(i)
def f():
i = 2
g()
f()
# 结果:
1
解释:执行到f()
时,python会检查代码并填充f
的局部命名空间{i: 2}
,执行到g()
时,创建g
的局部命名空间{i: 1}
,执行print(i)
时会先从局部命名空间找起,所以结果为1
(5)用del 删除命名空间中的键值对,即删除变量
def f():
y=1
del y
print(y)
f()
#错误:UnboundLocalError: local variable 'y' referenced before assignment
#去掉"del y"语句后,运行正常
(6)最后再举一个例子巩固一下:
i = 1
def f():
i = 2
def g():
print(i)
return g
func = f()
func()
print(i)
# 结果:
2
1