一、函数对象
函数是第一类对象:函数名指向的值可以被当做参数传递
1.函数名可以被传递
def func(): print('from func') f = func #函数名可以被传递,这里用一个变量名赋值 func() #from func print(f) #这里打印的是函数的内存地址 f() #f()等价于 func()
2.函数名可以被当做参数传递给其他函数
def func(): print('from func') def index(args): print(args) #等价于print(func) 打印函数func内存地址 args() #运行函数func() 执行内部代码 print('from index') index(func) #函数名func当做参数名传递到index函数中 #结果 #<function func at 0x0000001A50EE0E18> #from func #from index
3.函数名可以被当做函数的返回值
def index(): print('index') def func(): print('func') return index res = func() #返回值是 index print(res) #打印函数名index的内存地址 res() #调用运行index()函数 #结果 #func #<function index at 0x0000001DB2490E18> #index
4.函数名可以被当做容器类型的参数
def func(): print('func') print(func()) #func None l = [1,2,func,func()] print(l) #结果 func None func #为什么结果有这个,因为在l调用了函数func(),所以打印一个func [1, 2, <function func at 0x0000009769AF0E18>, None]
二、函数调用 (在一个函数内部调用其他函数,可以将复杂的逻辑简单化)
def index(): func() print('index') def func(): print('func') index() #调用index()之后,func()已经被定义了,可以被调用
三、名称空间
名称空间是什么:就是存放变量名和变量值的内存地址的绑定关系的地方
名称空间的分类:
1.内置空间名称:python解释器提前给你定义好的名字(已经存放在内置名称空间了)
就是一些内置函数:比如 len()/max()....
2.全局名称空间:文件级别的代码
3.局部名称空间:函数体内创建的名字都属于局部名称空间
def func(): username = 'jason' #这个username是局部名称空间 print(username) func()
总结:生命周期
内置名称空间:只要python解释器已启动立马创建 关闭python解释器的时候内置名称空间自动销毁(针对于python解释器)
全局名称空间:只要你运行py文件的时候会自动创建 py文件程序运行结束自动销毁 (针对于py文件)
局部名称空间:函数被调用的时候创建 函数结束就销毁(针对于函数的调用开始结束)
四、名称空间的查找顺序
注意:先要确定好你当前在哪(在哪个空间)
查找顺序
1.如果你现在在全局: 全局 >>>内置 (先从全局找再到内置)
2.如果你现在在局部:局部>>全局>>内置(先从局部找再到全局再到内置)
例题:
局部命名空间:先定位要打印的len属于什么空间,因为它是在函数里面的变量,所以它是局部名称空间,先找局部变量,正好函数里面有一个变量名赋值,所以这个len就从这取值
len = '我是全局名称空间的len' def func(): len = '我是局部名称空间的len' print(len) func()
全局和局部:我们先来看红色的len,这个len在全局的位置,查找顺序先从全局开始,不会找到函数内部的局部。在全局里面已经有一个定义的len,所以用这个 '我是全局名称空间的len'。然后函数里面的len就和上面的一样了。
len = '我是全局名称空间的len' def func(): len = '我是局部名称空间的len' print(len) print(len) # 我现在站在的是全局的位置 func()
#结果
#我是全局名称空间的len
#我是局部名称空间的len
局部:打印的x在局部位置,在本身函数没有,所以就往上一个找局部,找到有一个x。
def func(): x = 1 def index(): print(x) # 1 return index res = func() x = 999 res()
全局:如果把上一道题的局部x删掉,就要到全局里面找,找到x=999在函数调用之前已经定义了,最后结果就是999
def func(): def index(): print(x) # 999 return index res = func() x = 999 res()
全局:x定位到局部,但是在inner里面找不到,outer里面也找不到,所以x是使用全局,后面的inner在哪里调用,x都是在全局找值
x=111 def outer(): def inner(): print('from inner',x) #from inner 111 return inner f=outer() def func(): x=333 f() func()
总结:函数在定义阶段就已经固定查找名字的顺序了,不会因为函数调用的位置改变而改变
五、作用域
作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域
全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用,全局有效
局部作用域:局部名称空间、只能在局部范围生效
global和nonlocal
global:在局部修改全局的不可变数据类型
在下面这个如果不是用global,后面x和username打印的全局的值,就是1,jason。如果你使用了global,改变了全局变量的值,在下面设置x = 999,username = 'egon',打印的值也是这个。
nonlocal:局部修改局部(函数嵌套)
如果没有加nonlocal,x在局部找值,x=1。nonlocal 修改了前面x的值,在打印的时候变成2
总结:global:局部修改全局,如果有多个,用逗号隔开
nonlocal:局部修改局部,如果有多个,用逗号隔开