一、装饰器

参考: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('测试代码执行完毕')

三、装饰器的执行顺序是从里到外的。