名称空间
用来存放名字的地方,有三种名称空间:内置名称空间,全局名称空间,局部名称空间。
1 比如执行test.py: 2 3 python test.py 4 1、python解释器先启动,因而首先加载内置名称空间 5 2、执行test.py文件,然后以文件为基础,加载全局名称空间 6 3、在执行文件的过程中如果调用函数,则临时产生局部名称空间
名称的加载顺序是先加载内置名称空间,再加载全局名称空间,最后是局部名称空间,所以,如果在全局名称空间中使用局部名称空间,是错误的,因为根本就找不到。
而在函数调用时查找名字的顺序是:局部名称空间—>全局名称空间—>内置名称空间。
作用域
首先来谈一下什么是作用域?先看一个例子:
1 b = 20 2 def func1(): 3 a = 10 4 print(a) 5 print(b) 6 7 def func2(): 8 print(b) 9 # print(a) 10 11 func1() 12 func2()
上面这段代码虽然简单,却可以很好的说明了函数作用域的问题,如上,如果注释掉函数func2的print(a)这一句,程序可以正常运行,但是如果加上这一句就出错,出错的原因是a没有定义,为什么b在两个函数中都可以引用,而a只能在func1中使用呢?这就是因为a的作用域的问题了。
变量作用域:
①L(Local)局部作用域
②E(Enclosing)闭包函数外的函数中
③G(Globa)全局作用域
④B(Built-in)内建作用域
以 L –> E –> G –>B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,最后去内建中找。
那么这具体是什么意思呢?
如上面的例子中,由名称空间的加载可知调用函数func1时产生func1的局部名称空间,而a就在该空间内,执行函数func1时从该名称空间中查找a,所以func1可以找到a。
但是函数func2的局部名称空间中却没有变量a,所以找不到,那就去全局名称空间找,也没有,所以出错。(Enclosing是对于闭包来说的)
这就说明a的作用域只能作用于函数func1。而b属于全局名称空间,属于全局变量,因此其可被func1和func2调用。
global,nonlocal关键字:
当内部作用域想修改外部作用域的变量时,要用到global,nonlocal关键字。
global 关键字用于局部作用域修改全局作用域时在局部变量前加上global。
nonlocal 关键字用于要修改嵌套作用域(即Enclosing,外层非全局作用域)。
1 a = 10 2 def func(): 3 global a 4 a += 3 5 print(a) 6 7 func()
这是一个很简单的使用global关键字,如果注释掉global a 这一句,程序会报错。
1 def func1(): 2 n = 0 3 4 def func2(): 5 nonlocal n 6 x = n 7 n += 1 8 return x 9 10 return func2 11 12 13 c = func1() 14 print(type(c)) # 可以看到c是一个函数对象 15 print(c()) # 执行c()其实就是执行func2()
这是一个简单的闭包,可以看到首先是函数func1里嵌套了一个函数func2,func2调用了func1的内部变量。如果注释掉nonlocal n的话会出错。
闭包:
闭包就是能够读取其他函数内部变量的函数,即定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。