Python 装饰器@wraps作用-使用记录

左手的ㄟ右手 2022-02-21 10:31 599阅读 0赞

1. 先看一段代码

  1. def is_login(func):
  2. def foo(*args,**kwargs):
  3. return func(*args,**kwargs)
  4. return foo
  5. def test():
  6. print('我是:',test.__name__)
  7. @is_login
  8. def test1():
  9. print('我是:',test1.__name__)
  10. @is_login
  11. def test2():
  12. print('我是:',test2.__name__)
  13. test()
  14. test1()
  15. test2()
  16. >>>>
  17. 我是: test
  18. 我是: foo
  19. 我是: foo

可以发现函数的函数名即 __name__已被装饰器改变

2.那我们来增加@wraps

  1. from functools import wraps
  2. def is_login(func):
  3. @wraps(func)
  4. def foo(*args,**kwargs):
  5. return func(*args,**kwargs)
  6. return foo
  7. def test():
  8. print('我是:',test.__name__)
  9. @is_login
  10. def test1():
  11. print('我是:',test1.__name__)
  12. @is_login
  13. def test2():
  14. print('我是:',test2.__name__)
  15. test()
  16. test1()
  17. test2()
  18. >>>>
  19. 我是: test
  20. 我是: test1
  21. 我是: test2

结论:

可以看见@wraps可以保证装饰器修饰的函数的__name__的值保持不变


补充:装饰的优化

以时间装饰器为例,进行优化

  • 装饰器的统一模板

    from functools import wraps

    对函数的装饰器, 对类func最好为cls

    def decorate(func):

    1. @wraps(func)
    2. # 增添或修改功能的函数
    3. def wrapper(*args,**kwargs):
    4. # 执行被装饰的函数
    5. result = func(*args,**kwargs)
    6. # 返回结果
    7. return result
    8. # 返回内层函数
    9. return wrapper

普通–时间装饰器

  1. from functools import wraps
  2. import time
  3. from random import randint
  4. def use_time(func):
  5. @wraps(func)
  6. def wrapper(*args,**kwargs):
  7. st_time = time.time()
  8. result = func(*args,**kwargs)
  9. end_time = time.time()
  10. print(f'{func.__name__}函数use_time:{end_time-st_time}s')
  11. return wrapper
  12. @use_time
  13. def foo():
  14. time.sleep(randint(1,3))
  15. for _ in range(3):
  16. foo()
  17. #输出
  18. >>>>
  19. foo函数use_time:1.0007495880126953s
  20. foo函数use_time:3.0018675327301025s
  21. foo函数use_time:3.0030477046966553s

下面对改装饰器进行优化(解耦)

  • 可以发先上面时间装饰器计算的结果,只能在控制台上打印
  • 那我们怎样才能将它输出为日志呢???
  • 我们需要将他的结果进行自定输出

    在增加一层函数

    from functools import wraps
    import time
    from random import randint

    def record(output):

    1. def use_time(func):
    2. @wraps(func)
    3. def wrapper(*args,**kwargs):
    4. st_time = time.time()
    5. result = func(*args,**kwargs)
    6. end_time = time.time()

    print(f’{func.name}函数use_time:{end_time-st_time}s’)

    1. output(func.__name__, end_time-st_time)
    2. return wrapper
    3. return use_time

    改装饰器的结果就可以自定义了,下面以print函数为例

    @record(print)
    def foo():

    1. time.sleep(randint(2,5))

    for _ in range(3):

    1. foo()

    >
    foo 3.000645875930786
    foo 4.003818988800049
    foo 2.0020666122436523


结果输出日志

  • 只需要自己定义一个函数

    def write_log(name,content):

    1. with open('./time.log','a')as f:
    2. f.write(f'{name}耗时:{content}\r\n') # \r\n 换行

    只需要将装饰器改为@record(write_log)

    @record(write_log)
    def foo():

    1. time.sleep(randint(2,5))

    for _ in range(3):

    1. foo()

效果如下

效果如图

发表评论

表情:
评论列表 (有 0 条评论,599人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Python 装饰如何使用

    装饰器(Decorator) 是 Python 里的一种特殊工具,它为我们提供了一种在函数外部修改函数的灵活能力。它有点像一顶画着独一无二 @ 符号的神奇帽子,只要将它戴在函数

    相关 Python @functools.wraps作用

    1:装饰器是干什么用的? 为了对一个函数在运行期的功能的拓展 2:装饰器加上之后产生的问题: 解释器认为函数本身发生了改变,其函数本身的属性改变了,在某些情况下——比如测

    相关 浅析python中@装饰作用

    要了解python中@装饰器的作用,首先要记住这么几点: 1. 装饰器符号“@”属于语法糖,什么意思呢?就是说,我不按照@装饰器的语法要求来写,而是按照一般python的语