命名空间
命名空间(Namespace)是从名称到对象的映射,命名空间的内容以字典形式给出,字典的key是已命名的变量或函数名称,value是这些变量或函数的值。简单地说就是将不同的名称分类 一般有三种命名空间: ①内置名称(built-in names), Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等。 ②全局名称(global names),模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。 ③局部名称(local names),函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)
1、命名空间查找顺序:
假设我们要使用变量 runoob,则 Python 的查找顺序为:
局部的命名空间去 -> 全局命名空间 -> 内置命名空间。
解释器会从命名空间中查找runoob,它先从局部空间查找,如果找到了它就会使用局部命名空间的变量runoob,即使全局命名空间也有变量runoob。 这就很容易理解为什么在函数内部声明的局部变量会覆盖掉在模块中声明的同名变量。 如果找不到变量 runoob,它将放弃查找并引发一个 NameError 异常:
NameError: name 'runoob' is not defined。
2、命名空间的生命周期:
命名空间的生命周期取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束。 (内置名称空间在 Python 解释器启动时就创建了,直到 Python 解释器退出时内置名称空间才失效。这使得我们可以在程序的任何位置使用内置名称空间内的名称,例如,id(),print()等函数。 模块名称空间当模块被引用时创建,直到 Python 解释器退出时模块名称空间才失效。 函数名称空间在函数被调用时创建,函数返回后失效。)因此,我们无法从外部命名空间访问内部命名空间的对象。
作用域
作用域就是一个 Python 程序可以直接访问命名空间的正文区域。在一个 python 程序中,直接访问一个变量,会从内到外依次访问所有的作用域直到找到,否则会报未定义的错误。(当在函数内部使用一个名称时,为了查找出该名称所引用的对象,Python 解释器先在函数名称空间查找,接着在模块名称空间查找,最后在内置名称空间查找,直到寻找到该名称为止。 )Python 中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值。(局部变量只能在其被声明的函数内部访问)变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。(比如函数作用域可以直接在函数中对变量进行读取操作和赋值操作;全局作用域意味着可以在全局对其进行进行读取操作和赋值操作,但是在函数内部对全局变量赋值操作时,需要使用global关键字)
def outer_function():
b = 20
def inner_func():
c = 30
a = 10
在函数inner_func中,我们可以对局部变量c进行读取操作和赋值操作,而只能对非局部变量b和全局变量a进行读取操作。当对b进行赋值时,一个新的名称将会被创建,这个新的名称处于inner_func函数局部名称空间中。对a进行赋值时也会在局部名称空间中创建一个新的名称。
有四种作用域: 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的命名空间
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。