函数是第一类对象---->函数名指向值的内存地址,可以被当作数据使用
1:可以被引用
2:可以当作参数传入函数
3:可以在函数内作为返回值
4:可以作为容器的元素
名称空间:用于存放函数名与值绑定关系的地方(但凡要查找值,一定得通过变量名,而变量名需要查找名称空间)
名称空间分为三类:
1.内置名称空间(在pyhon解释器运行时生效,关闭时失效)
2.全局名称空间(文件级别的变量,在python解释器解释运行python程序时生效,文件执行完毕后失效)
3.局部名称空间(在函数调用时生效,调用结束时失效---函数的参数和内部的名字都存放于局部名称空间)
加载顺序:内置名称空间--->全局名称空间---->局部名称空间
查找顺序:以当前位置为基准,向上查找(上不是前面),遵循局部--->全局--->内置的原则
# len = 111 # def func(): # len = 222 # print('基于局部查找',len) # # func() # print('基于全局查找',len) #--->当全局的len不存在时,查找内置的len名称
注:名字的查找顺序在函数定义阶段就固定死了(在定义阶段检测语法时,就已经确定!),与函数的调用位置无关(无论在何处调用函数都必须回到定义函数的地方去确定名字的查找顺序)!!!
例1
x = 111 def outter(): def intter(): print('from intter',x) return intter f=outter() f() x=222 f1 = outter() f1() x=333 #运行结果---> #from intter 111 #from intter 222 #intter内的x在定义阶段就决定了查找是从intter的局部作用域开始查找 #f() 最后找到的是全局的x=111 #f1()和f()一样,只是在调用之前,全局变量x指向了另一个整型对象
例2
x = 111 def outter(): def intter(): print('from intter',x) return intter f=outter() def func(): x=222 f() func() #运行结果---> #from intter 111 #这里在另一个函数内部调用了intter函数,虽然调用的时候f()上面有局部变量x, #但是名字查找顺序是在函数定义的时候就决定了,所以intter查找的仍然是全局变量的x
例3
x = 111 def outter(): def intter(): print('from intter',x) x = 1 return intter f=outter() #运行结果---> #UnboundLocalError: local variable 'x' referenced before assignment #报错,但是intter函数内的x查找的为intter函数自己的局部作用域中的x=1(注意,在函数定义阶段只检测语法,而不执行代码),但是在调用的时候,违背了变量的原则:先定义后调用
作用域:即名称空间作用的范围(生效)
作用域分为两类:
1.全局作用域(包括内置名称空间和全局名称空间名字)--->全局有效,在python程序执行的时候生效,伴随整个生命周期
2.局部作用域(只在函数内有效) --->局部有效,仅在函数调用时生效
在函数局部是不能修改全局的不可变类型变量,但是可以更改全局的可变类型变量
x =1 y = [1] def func(): x = 2 y.append(2) func() print(x,y) #运行结果--->1 [1, 2]
global:在局部声明一个名字来自于全局,可以在局部修改全局不可变类型变量
nonlocal:声明一个名字是来自外部作用域的(仍是局部),修改外层局部作用域的变量(不会改变全局变量)