高阶函数概念引入:满足下面两个条件之一便可以称为高阶函数
1:把一个函数的函数名当作实参传给另外一个函数(在不修改被装饰函数源码的基础上,为其增加功能)。
2:返回值中包含函数名(不修改被装饰函数的调用方式)。
下面是一段简单的高阶函数的代码使用条件1:
# Author:Ju BO ''' def bar(): print("in the bar") def test1(func): print(func) #----相当于打印bar这个函数在内存中的门牌号即内存地址 func()#----相当于bar(),调用bar这个函数 test1(bar)#----将bar函数名当作实参传给test1函数,test1函数用形参func来接收它。 '''
下面是一段在第一段代码的基础上新增了一些功能的高阶函数,从中也慢慢显示出了装饰器的影子。
#----改进------------------ #这段代码的功能为统计bar这个函数的运行时间 import time #---导入库 def bar(): time.sleep(3) #---等3秒 print("in the bar") def test1(func): start_time = time.time() #----截取开始时间 func() #---相当于bar(),运行bar这个函数 stop_time = time.time() #-----截取结束时间 print("the func run time is %s"%(stop_time - start_time))#---结束时间-开始时间 = bar的运行时间 test1(bar) #--将bar当作实参传递给test1
3:观察第二段代码发现貌似已经实现了装饰函数的功能,之前没有test1这个函数时,bar这个函数单纯的功能为打印“in the bar”,而现在test1这个函数附加了一个功能:计算bar这个函数的运行时间。那么根据装饰器的定义:本质是函数,目的是为其他函数添加附加功能,test1这个函数可以称之为装饰器吗?其实不然,暂时还不能称它为装饰器。因为要称之为装饰器,必须还要遵循2个原则:
(1):不能修改被装饰函数的源代码。
(2):不能修改被装饰的函数的调用方式。
4:为什么不能称test1为装饰器呢?原因很简单,依据3中提出的两个原则:首先明确bar是要被装饰的函数,test1该函数并没有修改它的源代码,满足第一条。但是显然第二条原则不满足,之前我们调用bar这个函数时是这样调用的:bar(),但是现在变成这样了:test1(bar),然后再在test1函数中调用bar,改变了bar这个函数的调用方式
下面是一段简单的高阶函数的代码使用条件2:返回值中包含函数名
import time def bar(): print("in the bar") def test2(func): print(func) return func test2(bar)#单纯这样写输出结果为bar函数的内存地址,不会将bar函数的运行结果 #test2(bar)#注意这个地方不能这样写:test2(bar()),这样写会将bar这个函数的返回值给test2函数,而不是将内存地址给test2,不符合高阶函数规则 ''' 可以这样写: t = test2(bar) print(t) ,t是什么东西呢?分析一下这段代码会怎么运行test2把bar传进来会立刻打印bar这个函数的内存地址,然后又把bar 这个内存地址返回回来,返回回来的结果给t,print(t),也会打印bar的内存地址 ''' 好像写了这么多,并没有什么用,怎么样才能变得有用呢?怎么办呢: t()#---代表什么意思呢,代表run bar这个函数,好像还没有什么用?下面注意: bar = test2(bar) bar() 观察上面代码:重要的地方到了:没有改变bar函数的源码,没有改变bar函数的调用方式,利用test2函数为bar函数新增了一项功能 :打印bar函数的内存地址
5:总结:循序渐进由浅入深,逐个击破高阶函数,最终实现装饰器功能。