名称空间与作用域
一、函数对象
函数是第一类对象
1、函数名是可以被引用
1 def func(): 2 print('from func') 3 a = func 4 a()
2、函数名可以当做参数传递
1 def index(x, y, func): 2 print(x, y) 3 func() 4 def foo(): 5 print('from foo') 6 index(1, 2, foo)
3、函数名可以当做返回值使用
1 def index(): 2 print('from index') 3 def func(a): 4 return a 5 b = func(index) 6 b()
4、函数名可以被当做容器类型的元素
1 def func(): 2 print('from func') 3 a = [1, '2', func] 4 f = a[2] 5 f()
1 # 简单购物车 2 def register(): 3 print('register') 4 def login(): 5 print('login') 6 def shopping(): 7 print('shopping') 8 def pay(): 9 print('pay') 10 def logout(): 11 print('logout') 12 func_dict = { 13 '1': register, 14 '2': login, 15 '3': shopping, 16 '4': pay, 17 '5': logout 18 } 19 def main(): 20 while True: 21 print(''' 22 1、注册 23 2、登录 24 3、购物 25 4、付款 26 5、退出 27 ''') 28 choice = input(">>>>").strip() 29 if choice == '5': 30 func_dict[choice]() 31 break 32 elif choice not in func_dict.keys(): 33 continue 34 else: 35 func_dict[choice]() 36 main()
二、名称空间
名称空间即存放名字与对象映射/绑定关系的地方。例如x=3,python会申请内存空间存放3,然后将名字x与3的绑定关系存放于名称空间中,执行时候会存在三种名称空间
名称空间分类:
⑴、内置名称空间:伴随着python解释器的启动而产生,关闭而回收,是第一个被加载的名称空间,用来存放一些内置名称,比如内建函数名len,print
⑵、全局名称空间:伴随着pytho文件的开始执行而产生,执行完毕而回收,是第二个被加载的名称空间,文件执行过程中产生的名字都会存放于该名称空间中
⑶、局部名称空间:伴随着函数的调用而尝试,函数结束调用而回收,函数的形参、函数的定义的名字都会被存在于该名称空间中
名称空间顺序:
加载顺序:内置名称空间 > 全局名称空间 > 局部名称空间
查找顺序:局部名称空间 > 全局名称空间 > 内置名称空间
函数内部使用的名字,在定义阶段就已经规定死了,与你的调用位置无关
1 x = 1 2 def dex(): 3 print(x) 4 def func(): 5 x = 2 6 dex() 7 func() 8 # 输出:1 9 10 x = 1 11 def index(arg = x): 12 print('x =', x, 'arg =', arg) 13 x = 2 14 index() 15 # 输出:x = 2 arg = 1
三、作用域
1、全局作用域与局部作用域
全局作用域:位于全局名称空间、内置名称空间中的名字属于全局范围。该范围内的名字全局存活、全局有效(在任意位置都可以使用)
局部作用域:位于局部名称空间的名字属于局部范围。该范围内的名字临时存活(即在函数调用时临时生成,函数调用结束后就释放)、局部有效(只能在函数内使用)
2、作用域与名字查找的优先级
⑴、在局部作用域查找名字时,起始位置是局部作用域,所以先查找局部名称空间,没有找到,再去全局作用域查找:先查找全局名称空间,没有找到再查找内置名称空间,最后没找到抛出异常
⑵、在全局作用域查找名字时,起始位置时全局作用域,所以先查找全局名称空间,没有找到再查找内置名称空间,最后没找到抛出异常
⑶、python支持函数的嵌套定义,在内嵌的函数查找名字时,会优先查找自己局部作用域的名字,然后由内而外一层层查找外部嵌套函数定义的作用域,都没有找到,则查找全局作用域
x = 1 def func(): x = 2 def index(): x = 3 print('内层:',x) index() print('外层:',x) func() # 结果为 内层:3 外层:2
在函数内,无论嵌套多少层,都可以查看到全局作用域的名字,若要在函数内修改全局名称空间的名字值,需要用到global关键字
1 x = 1 2 def func(): 3 global x 4 x = 2 5 func() 6 print(x) 7 # 输出结果:2
对于嵌套多层的函数,使用nonlocal关键字可以将名字声明为来自外部嵌套函数定义的作用域(非全局)
1 def f1(): 2 x = 1 3 def f2(): 4 x = 2 5 def f3(): 6 x = 3 7 def f4(): 8 nonlocal x 9 x = 4 10 print('f4:', x) 11 f4() 12 print('f3:', x) 13 f3() 14 print('f2:', x) 15 f2() 16 print('f1:', x) 17 f1() 18 # 输出结果: 19 f4:4 20 f3:4 21 f2:2 22 f1:1
ps:只有可变类型可以在局部修改外部变量的值
不可变类型的局部变量的修改无法影响上层,上上层