一、装饰器
参考:https://zhuanlan.zhihu.com/p/87353829
https://blog.csdn.net/zhh763984017/article/details/120072425
将函数作为对象
闭包概念
def outer(x): def inner(y): return x+y return inner # 返回一个函数对象
装饰器就是一个闭包,是在原有函数功能上的一个拓展1、无参数的装饰器:
def cost_time(func): def inner(): print(f'start time{time.time()}') func() return inner@ cost_timedef time_sleep(): time.sleep(5) # 在函数中加入新的功能实现
2、装饰器传参:
被装饰的函数带有参数
def cost_time(func): def inner(*args, **kwargs): print(time.time()) func(*args, **kwargs)@cost_timedef time_sleep(name): print(f'进程名字:{name}') time.sleep(5)
3、带参数的装饰器
装饰器函数带有参数,在@的时候需要传入一些必要的参数
import time def count_time_args(msg=None): # 需要多加一层函数,引入传参 def count_time(func): def wrapper(*args, **kwargs): t1 = time.time() func(*args, **kwargs) print(f"[{msg}]执行时间为:", time.time() - t1) return wrapper return count_time @count_time_args(msg="baiyu")def fun_one(): time.sleep(1) @count_time_args(msg="zhh")def fun_two(): time.sleep(1) @count_time_args(msg="mylove")def fun_three(): time.sleep(1) if __name__ == '__main__': fun_one() fun_two() fun_three()
二、类装饰器
当我们将类作为一个装饰器,工作流程:
通过__init__()方法初始化类
通过__call__()方法调用真正的装饰方法
1、不带参数的类装饰器
import time class BaiyuDecorator: def __init__(self, func): self.func = func print("执行类的__init__方法") def __call__(self, *args, **kwargs): print('进入__call__函数') t1 = time.time() self.func(*args, **kwargs) print("执行时间为:", time.time() - t1) @BaiyuDecoratordef baiyu(): print("我是攻城狮白玉") time.sleep(2) def python_blog_list(): time.sleep(5) print('''【Python】爬虫实战,零基础初试爬虫下载图片(附源码和分析过程) https://blog.csdn.net/zhh763984017/article/details/119063252 ''') print('''【Python】除了多线程和多进程,你还要会协程 https://blog.csdn.net/zhh763984017/article/details/118958668 ''') print('''【Python】爬虫提速小技巧,多线程与多进程(附源码示例) https://blog.csdn.net/zhh763984017/article/details/118773313 ''') print('''【Python】爬虫解析利器Xpath,由浅入深快速掌握(附源码例子) https://blog.csdn.net/zhh763984017/article/details/118634945 ''') @BaiyuDecoratordef blog(name): print('进入blog函数') name() print('我的博客是 https://blog.csdn.net/zhh763984017') if __name__ == '__main__': baiyu() print('--------------') blog(python_blog_list)
2、带参数的装饰器:
当装饰器有参数的时候,init() 函数就不能传入func(func代表要装饰的函数)了,而func是在__call__函数调用的时候传入的。
class BaiyuDecorator: def __init__(self, arg1, arg2): # init()方法里面的参数都是装饰器的参数 print('执行类Decorator的__init__()方法') self.arg1 = arg1 self.arg2 = arg2 def __call__(self, func): # 因为装饰器带了参数,所以接收传入函数变量的位置是这里 print('执行类Decorator的__call__()方法') def baiyu_warp(*args): # 这里装饰器的函数名字可以随便命名,只要跟return的函数名相同即可 print('执行wrap()') print('装饰器参数:', self.arg1, self.arg2) print('执行' + func.__name__ + '()') func(*args) print(func.__name__ + '()执行完毕') return baiyu_warp @BaiyuDecorator('Hello', 'Baiyu')def example(a1, a2, a3): print('传入example()的参数:', a1, a2, a3) if __name__ == '__main__': print('准备调用example()') example('Baiyu', 'Happy', 'Coder') print('测试代码执行完毕')
三、装饰器的执行顺序是从里到外的。