命名空间、作用域、取值顺序:
全局命名空间 、局部命令空间、内置命令空间的关系
当python解释器,对一个文件从上到下开始执行代码时,在内存中就为文件开个内存空间,在遇到变量 和 函数的定义时,就将 “变量名和值的关系”
及 “函数名和值的关系”保存在这个内存空间中,这块内存空间---叫做全局命令空间 或者叫做 全局名称空间。当整个py文件执行结束,全局名称空间从内存中释放。
全局命令空间中,保存在文件中,函数外的变量的名字 和 变量内容对应的内存地址,及 函数名和函数体对应的内存地的映射关系,可以叫做字典。
python解释器,对py文件,从上向下执行代码时,当遇到函数的调用或叫函数的执行时,会在内存中临时开辟一个内存空间,用来保存函数体内部定义的变量,及子函数映射关系。
当函数执行完毕,临时空间释放,这个临时空间, 我们称之为局部命令空间或局部名称空间。
内置命令空间;当py文件运行前,python解释器,加载到内存中,创建一个内存空间,用来存放内置函数input,print,len 及 类 list,tuple ,dict,str等的映射关系,这个内存
空间,我们称之为内置名称空间。内置命令空间的东本,全局命令空间,可以引用,调用,局部命令空间,也可以调用。同样,当解释器执行完py文件时,也退出,释放出该块内存空间。
在不同的空间的取值顺序:
在全局空间,即py文件的任意位置,除掉函数内部,引用对象,先在全局空间找,再到内置空间找,找不到就报错。 全局空间找 ----> 内置命令空间找
在局部空间,即函数内部的任意位置,引用对象,先在局部命名空间找,再到全局命令空间找,最后到内置空间找,找不到则报错。 局部空间找 ---> 全局名称空间找 ---> 内置命名空间找
作用域:
按照对象的作用范围,或者叫生命周期,分为全局作用域 ,局部作用域 。
全局作用域:对于内置名称空间,全局名称空间的对象 ,在整个文件执行过程中一直有效,直到文件执行结束,才结束其生命周期。因此我们说,内置空间、全局空间的对象它的作用范围,或者
作用域 ,为全局作用域。
局部作用域 :对于函数而言,当执行时,开辟了局部命名空间,局部命令空间的对象,仅在函数执行过程中,一直有效,函数执行结束 ,其生命周期结束。因此我们说,局部命名空间的对象它的作用
范围或者叫作用域,为局部作用域。
def len(obj): print(20) return 20 ret = len('hello world') # 我们知道python有一个内置函数len(),它是内置空间的,但是我们在全局命令空间调用len时,先到全局空间找,找到,后面有一个括号 ,就执行全局空间定义的len()函数 print(ret) # 相当于去内置空间len()函数进行了覆盖 def func8(obj): len(obj) # 在局部空间时,执行代码时,先在局部空间找函数名,没有找到,再到全局名称空间,找到执行 func8([1,3,5]) # 控制台打印 20 def func9(): def len(): print("局部命名空间") len() # 当执行func9()函数时,先定义局部空间中的len(),然后调用执行len(),先在局部空间去找,找到就执行 func9() # 控制台中打印输出 : 局部命名空间
print(len("str")) # 3 在全局空间没有找到len,再到内置命名空间 def func1(obj): return len(obj) # 函数执行时,先到局部命名内间找,没有找到再到全局命名空间找,没有找到,最后到内置名称空间找。 print(func1("sbcde")) # 5
在函数中, global 和 nonlocal 关键字的详解:
# nonlocal 关键字 ,只能用在子函数中,声明引用 上级的变量(直接上级没有,就到上上级,直到最顶端上级函数没有,就报错,先找到先引用 # nonlocal ---子函数对父函数中的变量的修改,直接父级没有,到上上父级到,不包括全局作用命令空间 def GrandFather(): count = 6 def Father(): count = 12 # 被下级函数,声明nonlocal count的引用 def son(): nonlocal count # 子函数中,用nonlocal声明一个变量,它会从它的上级函数去找,找到就引用 count = count + 1 print(count) son() Father() # 函数调用 GrandFather() # 输出结果,打印13 def GrandFather(): count = 6 # 被下级的 nonlocal count 找到,被引用 def Father(): # count = 12 # 现在我这一行代码,注释掉了 def son(): nonlocal count # 子函数中,用nonlocal声明一个变量,它会从它的上级函数去找,直接上级没有,就到上上级,找到就引用 count = count + 1 print(count) son() Father() # 函数调用 GrandFather() #$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$#################### # count = 10 # def GrandFather(): # # count = 6 # 这一行也注释掉 # # def Father(): # # count = 12 # 被下级函数,声明nonlocal count的引用 # # def son(): # nonlocal count # 子函数中,用nonlocal声明一个变量,它会从它的上级函数去找,找到就引用,但是不引用全局命令空间, # # 在所有上级,上上级....函数中都找不到,则报错:SyntaxError: no binding for nonlocal 'count' found # count = count + 1 # print(count) # son() # Father() # # GrandFather() # 子函数中的 nonlocal variable 引用自哪一层,那层及以下层全部发生改变 # global关键字 用在函数中,用于声明一个变量是全局命名空间的变量,如果在全局空间,没有找到,则创建,否则直接引用 # 第一种情况:函数中通过 global variable 声明的全局变量,在全局命令空间已经定义,直接引用 globalv = "I am a global variable" def func(): global globalv print(globalv) func() # 输出,打印: I am a global variable # 第二种情况:函数中通过 global variable 声明的变量,在全局命名空间没见有定义,那么在执行函数体过程中,会在全局名称空间 # 创建此变量,并用作用域,为全局作用域,即生命周期为整个文件 # def func2(): # global global_test # global_test = "I am from function" # print(global_test) # func2() # 屏幕打印:I am from function # print(global_test) # I am from function # 第三种情况:在函数中,声明了global variable ,但未调用过此函数,那么,这时在全局空间引用此变量,会报错 def func2(): global global_test global_test = "I am from function" print(global_test) # func2() # 把这一行代码注释掉,即虽然定义了函数,但是不调用,没有调用 ,就不会执行global global_test 语句,就不会在全局命令空间,创建变量 print(global_test) # 所以,在全局命名空间,调用变量时,报错: NameError: name 'global_test' is not defined 名称错误
对于global 和 nonlocal 关键字补充:
# 7题: # 7.1 # a = 2 # def wrapper(): # print(a) # wrapper() # 答:在局部空间,可以引用 全局命名空间的对象,所以此代码成立。 # # 7.2 # a = 2 # def wrapper(): # a += 1 # print(a) # wrapper() # 答: 此代码不成立,在局部名称空间,不能修改全局变量,需要声明为使用全局变量 # 解决办法: # def wrapper(): # global a # a += 1 # print(a) # wrapper() # print(a) # 7.3 题: def wrapper(): a = 1 def inner(): print(a) inner() wrapper() # 答 : 可以上级函数的命令空间的变量对下级函数而言,是可见的,可以直接引用 # 7.4 题: def wrapper(): a = 1 def inner(): a += 1 print(a) inner() wrapper() # 答 :代码不成立,下级函数引用上级函数里的变量,并修改,不成立,要修改的话,用nonlocal关键字声明。
最后总结: 在函数里可以直接引用 全局名称空间的 变量,但要在函数里--修改--全局名称空间的变量,则在函数里用global关键字声明 变量;
下级函数,可以直接引用上级函数里的变量,但下级函数要对上级函数(包括上上级....)的变量修改,则在函数内要用nonlocal关键字声明该变量
globals() 和 locals()函数:
#globals() 与 locals()函数: # glocals()函数 :返回执行这条命令的,当前作用域的全局变量的一个字典 # locals() : 返回执行这条命令时,当前作用域的局部变量的一个字典 # 当在文件中,函数外执行 时, 当前作用域 就是全局变量 所处的 全局命名空间,因此 globals() 与 locals() 结果 一样 print(globals()) print(locals()) def test(): a = 2 b = 3 print(globals()) print(locals()) # {'b': 3, 'a': 2} test() def test1(): a = 2 b = 3 def inner(): c = 5 d = 6 print(globals()) # 全局的不变 print(locals()) # {'d': 6, 'c': 5} inner() test1()
函数名可以作为容器类数据类型的元素,常用应用场景:
def register():
print("正在注册")
pass
def login():
print("正在登陆")
pass
def purchase():
print("购买功能正在开发中.....")
pass
def escape():
print("你已成功逃逸.....")
exit()
pass
function_dic = {1:register,2:login,3:purchase,4:escape}
while 1:
choice_num = input('''
1 .................. 注册
2 .................. 登陆
3 .................. 购买
4 .................. 退出
请输入【1-4】:
''')
if choice_num.isnumeric():
if int(choice_num) in list(range(1,5)):
function_dic[int(choice_num)]()