本文实例讲述了Python函数装饰器原理与用法。分享给大家供大家参考,具体如下:
装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
严格来说,装饰器只是语法糖,装饰器是可调用的对象,可以像常规的可调用对象那样调用,特殊的地方是装饰器的参数是一个函数
现在有一个新的需求,希望可以记录下函数的执行时间,于是在代码中添本文来源gaodai#ma#com搞*代#码9网#加日志代码:
import time #遵守开放封闭原则 def foo(): start = time.time() # print(start) # 1504698634.0291758从1970年1月1号到现在的秒数,那年Unix诞生 time.sleep(3) end = time.time() print('spend %s'%(end - start)) foo()
bar()、bar2()也有类似的需求,怎么做?再在bar函数里调用时间函数?这样就造成大量雷同的代码,为了减少重复写代码,我们可以这样做,重新定义一个函数:专门设定时间:
import time def show_time(func): start_time=time.time() func() end_time=time.time() print('spend %s'%(end_time-start_time)) def foo(): print('hello foo') time.sleep(3) show_time(foo)
但是这样的话,你基础平台的函数修改了名字,容易被业务线的人投诉的,因为我们每次都要将一个函数作为参数传递给show_time函数。而且这种方式已经破坏了原有的代码逻辑结构,之前执行业务逻辑时,执行运行foo(),但是现在不得不改成show_time(foo)。那么有没有更好的方式的呢?当然有,答案就是装饰器。
def show_time(f): def inner(): start = time.time() f() end = time.time() print('spend %s'%(end - start)) return inner @show_time #foo=show_time(f) def foo(): print('foo...') time.sleep(1) foo() def bar(): print('bar...') time.sleep(2) bar()
输出结果:
foo…
spend 1.0005607604980469
bar…
函数show_time就是装饰器,它把真正的业务方法f包裹在函数里面,看起来像foo被上下时间函数装饰了。在这个例子中,函数进入和退出时 ,被称为一个横切面(Aspect),这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。
@符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作
装饰器在Python使用如此方便都要归因于Python的函数能像普通的对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。
装饰器有2个特性,一是可以把被装饰的函数替换成其他函数, 二是可以在加载模块时候立即执行
def decorate(func): print('running decorate', func) def decorate_inner(): print('running decorate_inner function') return func() return decorate_inner @decorate def func_1(): print('running func_1') if __name__ == '__main__': print(func_1) #running decorate <function func_1 at 0x000001904743DEA0> # <function decorate.<locals>.decorate_inner at 0x000001904743DF28> func_1() #running decorate_inner function # running func_1