装饰器之高阶函数

高阶函数概念引入:满足下面两个条件之一便可以称为高阶函数

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这个函数的调用方式

5:综上上述只能称之为高阶函数:并且使用了高阶函数的第一个条件

下面是一段简单的高阶函数的代码使用条件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函数的内存地址

6:总结:循序渐进由浅入深,逐个击破高阶函数,最终实现装饰器功能。

猜你喜欢

转载自www.cnblogs.com/jb9527/p/10311860.html