前提须知(python解释器遇到函数的做法):
1.从python解释器开始执行后,就在内存中开辟了一块空间(全局命名空间)。
2.每次遇到一个变量的时候,就会把这个变量名和值得对应关系保存到这个内存的一个字典中,记录下来。
3.但是遇到函数定义的时候,解释器只会象征性地把函数读入内存,表示知道这个函数的存在,但是对函数内部的“变量”和逻辑毫不关心。
4.等执行到函数调用的时候,python解释器就会再开辟一块内存来存储函数里面的内存(局部命名空间)。这个时候,才会真正开始关注函数里面有哪些变量,而函数的变量会存储到新开辟的这个内存中。函数的变量只能在函数的内部使用,而且随着函数的执行完毕,这块空间就会被回收,内容就会被清空。
一.三种命名空间
1. 全局命名空间
2. 局部命名空间
3. 内置命名空间
从上面的解释,我们可以得出:
(1)代码开始时,python解释器创建的存储“变量:值”对应关系的内存空间叫做全局命名空间。
(2)在函数开始执行时,python解释器在内存中新开辟的内存空间叫做局部命名空间。
(3)内置命名空间,python内置,例如input,print等,在哪里都可以直接拿来使用。
二.三种命名空间的加载和取值顺序:
1.加载顺序:
内置命名空间(程序运行前加载)---> 全局命名空间(程序运行中加载,由上到下)--->局部命名空间(函数调用时加载)
2.取值顺序:
在局部调用时:局部命名空间--->全局命名空间--->内置命名空间
在全局调用时:全局命名空间--->内置命名空间
#在局部命名空间中:局部》全局》内置 #在全局命名空间中:全局》内置 #取值顺序都是单向的,不可逆。 x = 10 def foo(): x = 20 print(x) foo() #局部>全局>内置 print(x) #全局>内置 >>> 20 10
三.作用域
作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域等~
LEGB:
(1)Local(本地,局部):在局部空间中,即函数定义的变量。
(2)Enclosing(封闭):用在函数嵌套时。
(3)Global(全局):在当前这个py文件中
(4)Builtin(内置):在所有py文件中都可以使用,例如:input,str等。
四.global关键字
前提:局部命名空间对全局命名空间的变量可以引用,但是不能修改。
global作用:
1. 在局部名称空间声明一个局部变量。
2. 在局部名称空间可以对全局变量进行修改。
#一。结合前文的取值顺序, count = 1 def func1(): print(count) #取值顺序,局部命名空间(没有)----全局命名空间(有) func1() >>> 1 #二。如果在局部作用域中对全局变量进行修改,会如何? count = 1 def func1(): count = count +1 print(count) func1() >>>UnboundLocalError: local variable 'count' referenced before assignment ''' UnboundLocalError: local variable 'count' referenced before assignment 如果你在局部命名空间对一个变量进行修改,解释器就会认为这个变量要存在,已经在局部定义;如果没有 定义,就会引发以上报错。 '''
# 这个时候就是使用global的场景 # global的作用: ''' 1. 在局部命名空间声明一个局部变量。 2. 在局部命名空间对全局变量进行修改。 ''' count = 1 def func(): global count count = count +1 print(count) func() print(count) >> 2 2
五.函数嵌套
函数是python中的一级对象,可以在任何地方使用。包括函数里,此时的作用域属于封闭作用域Enclosing。
函数名的本质:函数也是一级对象。
一级对象:
(1)在运行时创建
(2)能够赋值给变量
(3)能够作为参数传递给函数
(4)能够作为函数的返回值
#函数嵌套范例一 def f1(): print('in f1') def f2(): print('in f2') f2() f1() >>> in f1 in f2 #函数嵌套范例二 def f1(): def f2(): def f3(): print('in f3') print('in f2') f3() print('in f1') f2() f1() >>> in f1 in f2 in f3
4.1 函数嵌套的作用域链
#函数作用链(一) def f1(): a = 1 def f2(): print(a) f2() f1() >>> 1 # 函数作用域(二) def f1(): a = 1 def f2(): def f3(): print(a) f3() f2() f1() >>> 1 # 函数的作用域(三) def f1(): a = 1 def f2(): a = 2 print('a in f2:',a) f2() print('a in f1:',a) f1() >>> a in f2: 2 a in f1: 1
总结以上:就是先从局部命名空间查找,再一级一级向上查找。
六.nonlocal关键字
1.在函数的外部必须有这个变量
2.在内部函数声明nonlocal变量之前,不能再出现同名变量。
3.在局部作用域修改父级作用域(非全局作用域的更外层作用域),并且引用的哪层,就从那层以下此变量发生变化。
def f1(): a = 10 def f2(): nonlocal a a = 30 f2() print('in the f1:',a) f1() >>> a in f2: 2 a in f1: 1 in the f1: 30 def f1(): a = 10 def f2(): def f3(): nonlocal a a = 30 print('in the f3:',a) print('in the f2:',a) f3() f2() print('in the f1:',a) f1() >>> in the f2: 10 in the f3: 30 in the f1: 30