1、命名空间查找顺序:
假设我们要使用变量 runoob,则 Python 的查找顺序为:
局部的命名空间去 -> 全局命名空间 -> 内置命名空间。解释器会从命名空间中查找runoob,它先从局部空间查找,如果找到了它就会使用局部命名空间的变量runoob,即使全局命名空间也有变量runoob。 这就很容易理解为什么在函数内部声明的局部变量会覆盖掉在模块中声明的同名变量。 如果找不到变量 runoob,它将放弃查找并引发一个 NameError 异常:
NameError: name 'runoob' is not defined。2、命名空间的生命周期:
命名空间的生命周期取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束。 (内置名称空间在 Python 解释器启动时就创建了,直到 Python 解释器退出时内置名称空间才失效。这使得我们可以在程序的任何位置使用内置名称空间内的名称,例如,id(),print()等函数。 模块名称空间当模块被引用时创建,直到 Python 解释器退出时模块名称空间才失效。 函数名称空间在函数被调用时创建,函数返回后失效。)因此,我们无法从外部命名空间访问内部命名空间的对象。有四种作用域: L(Local):最内层,包含局部变量,比如一个函数/方法内部。 E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。 G(Global):当前脚本的最外层,比如当前模块的全局变量。 B(Built-in): 包含了内建的变量/关键字等。,最后被搜索 规则顺序: L –> E –> G –>gt; B。 在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。
如下:
# Python 的一个内建值 int,我们首先将其赋值为 0,然后定义一个函数 fun1()。 >>> int = 0 >>> def fun1(): int = 1 def fun2(): int = 2 print(int) fun2()函数 fun1() 的作用就是调用函数 fun2() 来打印 int 的值。 调用函数 fun1():
>>> fun1() 2因为 local 中的 int = 2,函数将其打印出来。 将函数 fun2() 中的 int = 2 删除 :
>>> int = 0 >>> def fun1(): int = 1 def fun2(): print(int) fun2()调用函数 fun1():
>>> fun1() 1因为 local 找不到 int 的值,就去上一层 non-local 寻找,发现 int = 1 并打印。 而进一步删除函数 fun1() 中的 int = 1 :
>>> int = 0 >>> def fun1(): def fun2(): print(int) fun2()调用函数 fun1():
>>> fun1() 0因为 local 和 non-local 都找不到 int 的值,便去 global 中寻找,发现 int = 0 并打印。 若删除 int = 0这一条件:
>>> def fun1(): def fun2(): print(int) fun2()调用函数 fun1(): 因为 local、non-local、global 中都没有 int 的值,便去 built-in 中寻找 int 的值,即:
>>> fun1() <class 'int'>1、全局变量和局部变量
定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。2、global 和 nonlocal关键字
当内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字了。
用global修改全局变量 num:
num = 1 def fun1(): global num # 需要使用 global 关键字声明 print(num) num = 123 print(num) fun1() print(num) 输出: 1 123 123如果要修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量则需要 nonlocal 关键字:
def outer(): num = 10 def inner(): nonlocal num # nonlocal关键字声明 num = 100 print(num) inner() print(num) outer() 输出: 100 100另外有一种特殊情况,假设下面这段代码被运行:
a = 10 def test(): a = a + 1 print(a) test()执行后:
Traceback (most recent call last): File "test.py", line 7, in <module> test() File "test.py", line 5, in test a = a + 1 UnboundLocalError: local variable 'a' referenced before assignment错误信息为局部作用域引用错误,因为 test 函数中的 a 使用的是局部,未定义,无法修改。 修改 a 为全局变量,通过函数参数传递,可以正常执行输出结果为:
a = 10 def test(a): a = a + 1 print(a) test(a) 输出: 11或者使用global关键字将函数内a声明为全局变量:
>>> a =10 >>> def test(): ... global a ... a = a+1 ... print(a) ... >>> >>> test() 11参考: Python3 命名空间和作用域 Python 名称空间与作用域 解读Python的命名空间