• python装饰器详解


            python中的装饰器(decorator)一般采用语法糖的形式,是一种语法格式。比如:@classmethod,@staticmethod,@property,@xxx.setter,@wraps(),@func_name等都是python中的装饰器。

            装饰器,装饰的对象是函数或者方法。各种装饰器的作用都是一样的:改变被装饰函数或者方法的功能,性质。

            下面主要讲解@wraps(),@func_name,类装饰器这两种装饰器。

    目录

    一,装饰器的官方定义

    二,给某个函数加上一个装饰器

    1,一般写法

    2,标准的语法糖写法

    二,给某个函数加上多个装饰器

    2.1 给一个函数添加两个装饰器

    2.2 当一个函数具有两个装饰器时的执行顺序

    三,带参数装饰器的典型写法

    四,@wraps()语法糖(了解)

    五,类装饰器

    1,不带参数的类装饰器

    2,带参数的类装饰器


    一,装饰器的官方定义

            装饰器本质上是一个Python函数(其实就是闭包),它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。装饰器用于有以下场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。

    二,给某个函数加上一个装饰器

    1,一般写法

    1. # 为函数添加一个统计运行时长的功能
    2. import time
    3. def how_much_time(func):
    4. def inner():
    5. t_start = time.time()
    6. func()
    7. t_end = time.time()
    8. print("一共花费了{0}秒时间".format(t_end - t_start, ))
    9. return inner
    10. # 将增加的新功能代码以及被装饰函数运行代码func()一同打包返回,返回的是一个内部函数,这个被返回的函数就是装饰器
    11. def sleep_5s():
    12. time.sleep(5)
    13. print("%d秒结束了" % (5,))
    14. def sleep_6s():
    15. time.sleep(6)
    16. print("%d秒结束了" % (6,))
    17. sleep_5s = how_much_time(sleep_5s)
    18. # 因为sleep_5s函数的功能就是睡5秒钟,虽然增加了统计运行时间的功能,但是他本身功能没变(还是睡5秒钟),所以仍然用原来函数名接收增加功能了的自己
    19. sleep_6s = how_much_time(sleep_6s)
    20. t1 = threading.Thread(target=sleep_5s)
    21. t2 = threading.Thread(target=sleep_6s)
    22. t1.start()
    23. t2.start()
    24. # 5秒结束了
    25. # 一共花费了5.014161109924316秒时间
    26. # 6秒结束了
    27. # 一共花费了6.011810302734375秒时间

    2,标准的语法糖写法

    1. # 为函数添加一个统计运行时长的功能
    2. import time
    3. import threading
    4. def how_much_time(func):
    5. def inner():
    6. t_start = time.time()
    7. func()
    8. t_end = time.time()
    9. print("一共花费了{0}秒时间".format(t_end - t_start, ))
    10. return inner
    11. @how_much_time
    12. # @how_much_time等价于sleep_5s = how_much_time(sleep_5s)
    13. def sleep_5s():
    14. time.sleep(5)
    15. print("%d秒结束了" % (5,))
    16. @how_much_time
    17. def sleep_6s():
    18. time.sleep(6)
    19. print("%d秒结束了" % (6,))
    20. t1 = threading.Thread(target=sleep_5s)
    21. t2 = threading.Thread(target=sleep_6s)
    22. t1.start()
    23. t2.start()

    二,给某个函数加上多个装饰器

            在这里以添加两个装饰器为例。

    2.1 给一个函数添加两个装饰器

    1. # 为函数添加一个统计运行时长的功能以及日志记录功能
    2. import time
    3. import threading
    4. def how_much_time(func):
    5. print("how_much_time函数开始了")
    6. def inner():
    7. t_start = time.time()
    8. func()
    9. t_end = time.time()
    10. print("一共花费了{0}秒时间".format(t_end - t_start, ))
    11. return inner
    12. def mylog(func):
    13. print("mylog函数开始了")
    14. def inner_1():
    15. print("start")
    16. func()
    17. print("end")
    18. return inner_1
    19. @mylog
    20. @how_much_time
    21. # 等价于mylog(how_much_time(sleep_5s))
    22. def sleep_5s():
    23. time.sleep(5)
    24. print("%d秒结束了" % (5,))
    25. if __name__ == '__main__':
    26. sleep_5s()
    27. #how_much_time函数开始了
    28. #mylog函数开始了
    29. #start
    30. #5秒结束了
    31. #一共花费了5.012601613998413秒时间
    32. #end

    2.2 当一个函数具有两个装饰器时的执行顺序

    三,带参数装饰器的典型写法

    四,@wraps()语法糖(了解)

            因为装饰器实质是就是一个函数,是一个被修饰过函数,他与原来未被修饰的函数是两个不同的函数对象。

            所以,这个装饰器丢失了原来函数对象的一些属性,比如:__name__,__doc__等属性。使用wraps语法糖可以保留这些属性。

    五,类装饰器

            类装饰器这个写法,主要思路就是返回一个增加了新功能的函数对象,只不过这个函数对象是一个类的实例对象。由于装饰器是可调用对象,所以必须在类里面实现__call__方法,这样由类生成的各种实例加上()就可以运行了。

    1,不带参数的类装饰器

    1. import time
    2. class Decorator:
    3. def __init__(self, func):
    4. self.func = func
    5. def defer_time(self):
    6. time.sleep(5)
    7. print("延时结束了")
    8. def __call__(self, *args, **kwargs):
    9. self.defer_time()
    10. self.func()
    11. @Decorator
    12. def f1():
    13. print("延时之后我才开始执行")
    14. f1()

    2,带参数的类装饰器

    1. import time
    2. class Decorator:
    3. def __init__(self, func):
    4. self.func = func
    5. def defer_time(self,time_sec):
    6. time.sleep(time_sec)
    7. print(f"{time_sec}s延时结束了")
    8. def __call__(self, time):
    9. self.defer_time(time)
    10. self.func()
    11. @Decorator
    12. def f1():
    13. print("延时之后我才开始执行")
    14. f1(5)

  • 相关阅读:
    SpringCloudAlibaba微服务分布式架构
    从Hadder看蛋白质分子中的加氢算法
    集群搭建(1)
    设计模式-装饰器模式
    人工智能热潮推动光芯片与光器件需求飙升
    用C++做数据分析 - 唐代诗人的朋友圈
    Session会话追踪的实现机制
    ubuntu 20.4安装k8s 1.24.0(使用containerd)
    Redis常用实战场景及总结复习
    台式电脑怎么格式化重装系统
  • 原文地址:https://blog.csdn.net/weixin_44992737/article/details/125868592