名称空间与作用域
一、名称空间
名称空间:就是名字与地址的对应关系,可以被python解释器遍历查找,采用堆栈存储方式
队列存储方式:先进先出
堆栈存储方式:先进后出,优先访问到的是最后添加到结构中的变量在内置、全局、局部三个位置,只要出现了变量的定义,一定产生了自己名称空间中的民资,这些名字之间没有冲突
三种名称空间:1. 内置名称空间:系统级,一个,随解释器执行而产生,解释器停止而销毁
2. 全局名称空间:文件级,多个,随所属文件加载而产生,稳健运行完毕而销毁
3. 当前名称空间:函数级,多个,随所属函数执行而产生,函数执行完毕而销毁【注】文件的if,while,for,with这些能产生缩减的关键字并不能产生名称空间
加载顺序:内置名称空间 > 全局名称空间 > 当前名称空间
在局部调用:局部命名空间 > 全局命名空间 > 内置命名空间
二、函数嵌套
2.1 函数的嵌套调用
def max2(x,y): m = x if x>y else y return m def max4(a,b,c,d): res1 = max2(a,b) res2 = max2(res1,c) res3 = max2(res2,d) return res3 # max4(23,-7,31,11)
2.2 函数的嵌套定义
概念:在一个函数的内部定义另一个函数
为什么要有函数的嵌套定义:1)函数fn2想直接使用fn1函数的局部变量,可以将fn2直接定义到fn1的内部,这样fn2就可以直接访问fn1的变量
2)函数fn2名字就变成fn1的局部变量了,正常只能在fn1内部使用,想在外部使用,可以将fn2函数对象作为fn1函数的返回值
3)在外部也用同名的变量fn2来接收fn1函数 的执行结果(fn1函数的返回值),那么fn2也就是在外部被调用
def f1(): def f2(): def f3(): print("in f3") print("in f2") f3() print("in f1") f2() f1()def f1(): def f2(): def f3(): print('from f3') f3() f2() f1() f3() #报错,为何?
三、作用域
3.1 作用域范围
作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。
全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效
局部作用域:局部名称空间,只能在局部范围内生效
【注】
1. 不同作用域之间名字不冲突,已达到名字的重用
2. 每个作用域优先使用自己作用域的名字,没有再找更大的名称空间的名字,直到内置,还没有就报错
3. 查找顺序:局部作用域 > 嵌套作用域 > 全局作用域 > 内置作用域print(len) # <built-in function len> len = 10 def f1(): len = 20 print(len) # 20 def f2(): len = 30 print(len) # 30 f2() f1() print(len) # 10
3.2 global关键字
1.作用:将局部的变量提升为全局变量 # 1.全局没有同名变量,直接提升局部变量为全局变量 # 2.有同名全局变量,就是统一全局与局部的同名变量 # -- 如果局部想改变全局变量的值(发生地址的变化),可以用global声明该变量 num = 888 def fn1(): global num # print(num) # 没有global修饰,num就是自己局部的变量 # 有global修饰,num就是全局的num,全局中只能出现一个num,如果出现了值的改变,大家一起变 num = 666 def fn2(): print(num) # 666 fn1() fn2()
3.3 nolocal关键字
1.作用:将局部的变量提升为全局变量 # 1.全局没有同名变量,直接提升局部变量为全局变量 # 2.有同名全局变量,就是统一全局与局部的同名变量 # -- 如果局部想改变全局变量的值(发生地址的变化),可以用global声明该变量 num = 888 def fn1(): global num # print(num) # 没有global修饰,num就是自己局部的变量 # 有global修饰,num就是全局的num,全局中只能出现一个num,如果出现了值的改变,大家一起变 num = 666 def fn2(): print(num) # 666 fn1() fn2()