修饰器的概念和作用 什么是修饰器
装饰器, 也被称作修饰器, 其本身属于一个函数, 能够给原先既有的函数或者方法上面添加某些额外的功能。
修饰器的作用
概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
比如说, 这个函数具备注册的特性, 但有时, 当这个用户开展这个行动时, 他属于已注册的用户, 而我所写的这个函数已完成, 不想对其进行改动了, 那么, 我们能够借助修饰器为这个函数增添一个登录的功能。
它常常被运用于存在切面需求的情景之中, 像是: 插入日志的情景, 性能被测试的情景, 针对事务进行处理的情景, 缓存相关的情景, 权限校验相关的情景等等。装饰器乃是解决这类问题的极为出色的设计, 有了装饰器, 我们便能够从中抽离出数量众多的、同函数功能其自身并无关联的雷同代码, 并且还能持续进行重用。从需求开始说起。
引入
现在,假设我们有一个函数
def foo(): print('in foo()') foo()有这样的情况, 就是为了对这个函数的复杂度进行检查, 而在网络编程里程序的延时是相当要紧的, 所以需要去测算运算时间, 于是增加了计算时间的功能, 进而有了下面这样的代码:。
import time def foo(): start = time.clock() print('in foo()') end = time.clock() print('in foo()') foo()这儿仅仅写了个函数, 要是想测定好几个函数的延迟, 鉴于必定要晓得start跟end, 因而势必得写在程序起始与末尾, 但难道每个程序都这般复制粘贴吗? 虽说可行, 然而借助设计模式把功能以及数据部分拆分, 类似操作中再把这测量时长的函数分离出去, 就如同C++里能把这测量时长的函数转成类那种情况一样, 通过调用此类别, 赋予不一样的函数去度量不同函数的执行耗时。在中,由于函数实际上就是对象,所以可以利用类似的方法实现:
import time def foo(): print('in foo()') def timeit(func): start = time.clock() func() end =time.clock() print('Time Elapsed:', end - start) timeit(foo)在这里函数func()能够被用来指定函数, 话虽如此, 要是我不打算填这个函数, 并且这个功能函数没办法被修改成类似的形式, 这种情况下要怎么处理呢? 我们所需要的是怎样做到最大限度地减少改动:。
import time def foo(): print('in foo()') # 定义一个计时器,传入一个,并返回另一个附加了计时功能的方法 def timeit(func): # 定义一个内嵌的包装函数,给传入的函数加上计时功能的包装 def wrapper(): start = time.clock() func() end =time.clock() print('Time Elapsed:', end - start) # 将包装后的函数返回 return wrapper foo = timeit(foo) #可以直接写成@timeit + foo定义,python的"语法糖" foo()在这个代码里, (foo)并非直接产生调用的效果, 而是返回一个跟foo参数列表相同的函数(实际上是函数回调), 此时此地这个foo跟之前的foo不一样!因为这时的foo有了这样的功效, 简言之就是能使你在装饰前后执行代码, 而不用去改变函数自身的内容, 装饰器是一个函数, 并且它的参数是另一个函数。
修饰器本质
针对于这个, 被称作@注解语法糖之 - Sugar而言, 在你凭借某个@用以修饰某个函数func之际, 情形如下所展现的:
@decorator def func(): pass其解释器会解释成下面这样的语句:
func = decorator(func)等等, 难道这不是将一个函数当作参数传入到另一个函数里, 随后再进行回调吗? 没错, 然而, 我们得留意, 这里还存在一个赋值语句, 它把这个函数的返回值又赋值回原来的 func 这个呢!按照《函数式编程》当中 first class 的定义来说, 你能够把函数用作变量一样发挥作用, 所以, 必须返回一个函数给 func 才行, 这就是所谓的 order 高阶函数了, 要不然, 后续在调用 func() 时就会出现错误。
注意 个人总结
实际上, 修饰器跟一个函数比较相像, 然而修饰器会把被修饰的函数当作形参看待, 首先去执行修饰器里面的语句, 接着返回传递进来的函数对象(别的函数对象也可以), 随后调用返回出来的那个函数。