需求:实现一个可以统计代码的运行时间-CSDN博客
装饰器就是我们常见的在类或函数上的@装饰器,比如unittest里@ddt,它可是一种好用的工具。如果你同事写了一坨代码,你想给这一坨代码扩展新的功能,这个时候就用到了装饰器,它的神奇在于,它既不改变原功能函数的内部代码,还不改变调用方法的情况下,就给你同事的这坨代码扩展了新的功能。该说不说,设计装饰器的大佬真是给我们带来了极大的方便。
装饰器原理:
@装饰器 等同于调用装饰器,就是把被装饰的函数,当成参数传入装饰器中,保存在封闭作用域中。
书接上回,上篇就是用装饰器实现了统计代码运行时间的功能, 上篇的函数装饰器,都是用闭包的形式;什么又是闭包呢?
闭包:简单的说就是 一个函数在一个封闭作用域内
形式:
一个函数嵌套一个函数;
外层函数return返回内层函数;
这样内层函数就保证在外层函数这个封闭作用域内了
在内层函数里:
扩展的代码1
被装饰的函数
扩展的代码2
这就给被装饰的函数扩展新功能啦。
def decorator(func):def wrapper():print("扩展的代码1")func()print("扩展的代码2")return wrapper@decorator # work = decorator(work) def work():print("----------写代码-----------")work()
这样一个基本的装饰器就完成啦。
这个时候,我们装饰的函数有参数,要怎么做呢?
def decorator(func):def wrapper(*args, **kwargs):print("-----------开机,打开软件--------------")res = func(*args, **kwargs)print("------------关机,底薪到手--------------")return resreturn wrapper@decorator # work = decorator(work) def work(a, b):print("----------写代码-----------")return a + bwork(10, 30)
再复杂一点,我们装饰器本身带有参数呢?
@decorator(5) =====》等同于 被装饰的函数 = decorator(5)(被装饰的函数)
def decorator(n):"""最外层的参数n,接收装饰器传进来的值"""def wrapper(func):"""第二层参数func,接收被装饰的函数"""def wrapper1(*args, **kwargs):"""第三次参数,接收被装饰的函数调用时传进来的参数"""print(n)print("装饰器扩展的功能代码1")res = func(*args, **kwargs)print("装饰器扩展的功能代码2")return resreturn wrapper1return wrapper@decorator(5) # work = decorator(5)(work) def work():print("人生苦短,我学python")work()
至此,通过函数实现装饰器,就这些了。(提一句,装饰器有个副作用,问题也不大,在这儿就不介绍了。)
你就想啦,通过函数能实现装饰器,那能不能通过类实现装饰器呢?你是会举一反三的,当然可以啦。这个时候,你又学了一个魔术方法__call__,这个时候你就能通过类实现装饰器啦。
这个魔术方法有什么作用呢?类创建出来对象能不能调用,就取决于这个类中有没有魔术方法__call__。
import timeclass CountTime:def __init__(self, func):# func:是被装饰的函数,传入进来之后保存为func属性self.func = funcdef __call__(self, *args, **kwargs):st = time.time()# 调用原功能函数res = self.func(*args, **kwargs)et = time.time()print("函数执行的时间为:", et - st)return res@CountTime # ===> work = CountTime(work) 实例化对象 def work():time.sleep(2)work()
装饰器好神奇,怎么用好这个工具,还得看个人;用函数或者类实现装饰器,我这里都是装饰的函数,一样的,也可以去装饰器类,试着去写一下吧。