函数是第一类对象
所谓第一类对象:可以用标识符给对新命名,并且对象可被当做数据处理,
例如赋值、作为参数传递给函数,或者作为返回值return
因此,可用其他变量名引用这个函数对象
或将函数对象作为参数,传递给另一个函数:传参过程类似于一个赋值操作
def func(a,b): return a+b add = func print(func(1,2)) print(add(1,2))
def caller__func(f): return f(1,2) if __name__ == '__main__': print(caller__func(func))
运行结果:3
3
3
说明:局部变量f引用func函数,f实际指向了函数func
执行 return f(1,2)相当于执行return func(1,2)
函数对象vs函数调用
无论是把函数赋值给新的标识符,还是作为参数传递给新的函数,针对的都是函数对象本身,而不是函数的调用
eg:
def func(): return 'hello world' ref1 = func #将函数对象赋值给ref1 ref2 = func() #调用函数,将函数的返回值赋值给ref2 #判断两者类型 print(ref1) print(ref2) #可用callable函数验证某一变量或函数是否可调用 print(callable(ref1)) print(callable(ref2))
运行结果:<function func at 0x05535540>
hello world
True
False
闭包&LEGB法则
闭包,将组成函数的语句和对应的执行环境打包在一起得到的对象
闭包最重要的使用价值在于:封存函数执行的上下文环境;
闭包在其捕捉的执行环境(def语句块所在上下文)中,也遵循LEGB规则逐层查找,直至找到符合要求的变量,或者抛出异常。
对于嵌套函数,闭包将会捕捉内层函数执行所需的整个环境
闭包必需的三大条件:函数嵌套、内部函数引用外部变量、外部函数需返回内层函数
'闭包(函数嵌套):调用过程:将内部函数返回给外部函数' def FunX(x): print('-----------开始-----------') def FunY(y): print(y) return x*y print('-------------结束--------------') def FunZ(z): print(z) return x*z return FunY,FunZ y,z=FunX(3) print(y(4)) print(z(5))
其中的FunY和FunZ就是所谓的闭包,而FunY内部所引用过的y(FunZ内部所引用过的z)就是所谓的闭包变量。
内函数里运用了外函数的临时变量x,并且外函数的返回值FunY,FunZ是内函数的引用。这样就构成了一个闭包。
一般情况下,局部变量在函数返回时,就会被垃圾回收器回收,而不能再被使用。但闭包是一种特殊情况,当外函数的的变量在内函数使用时,即绑定给内部函数,延长生命周期
装饰器
封存上下文这一特性可被巧妙的用于现有函数的包装,从而为现有函数增加功能,即装饰器
装饰器就是闭包,但装饰器传入的参数是函数
因为python是一门胶水语言,在python一切皆是对象,python中全部都是引用类型
因此函数可以像变量一样被指向和传递。
原则:
1、不能修改被装饰函数的源代码。
2、不能修改被装饰函数的调用方式。
3、不能改变被装饰函数的执行结果。
装饰器对被装饰函数是透明的
def add(a,b): return a+b def checkParams(fn): def wrapper(a,b): if isinstance(a,(int,float)) and isinstance(b,(int,float)): return fn(a,b) else: print('变量a和b不能相加') return return wrapper if __name__ == '__main__': wrapper=checkParams(add) result=wrapper(2,3) print(result)
语法糖
def doupi(fn): def jiadoupi(): print('麻酱豆皮10块') return fn()+10 return jiadoupi def xiangcai(fnn): def jiaxiangcai(): print('麻酱香菜5块') return fnn()+5 return jiaxiangcai #语法糖 @xiangcai @doupi def diguo(): print('底锅:50') return 50 #aa=doupi(diguo) #aa=doupi(xiangcai(diguo)) #print(aa()) x=diguo() print(x)