美文网首页
对装饰器@wraps的解释(一看就懂)-- 并对装饰器浅谈

对装饰器@wraps的解释(一看就懂)-- 并对装饰器浅谈

作者: 憧憬001 | 来源:发表于2019-04-11 08:48 被阅读0次

    1. 先看一段代码

    def is_login(func):
        def foo(*args,**kwargs):
            return func(*args,**kwargs)
        return foo
    
    def test():
        print('我是:',test.__name__)
    
    @is_login
    def test1():
        print('我是:',test1.__name__)
    @is_login
    def test2():
        print('我是:',test2.__name__)
        
    test()
    test1()
    test2()
    
    >>>>
    
    我是: test
    我是: foo
    我是: foo
    

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

    2.那我们来增加@wraps

    from functools import wraps
    
    def is_login(func):
        @wraps(func)
        def foo(*args,**kwargs):
            return func(*args,**kwargs)
        return foo
    
    def test():
        print('我是:',test.__name__)
    
    @is_login
    def test1():
        print('我是:',test1.__name__)
    @is_login
    def test2():
        print('我是:',test2.__name__)
        
    test()
    test1()
    test2()
    
    >>>>
    我是: test
    我是: test1
    我是: test2
    

    结论:

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


    补充:装饰的优化

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

    • 装饰器的统一模板
    from functools import wraps
    # 对函数的装饰器, 对类func最好为cls
    def decorate(func):
        @wraps(func)
        # 增添或修改功能的函数
        def wrapper(*args,**kwargs):
                    # 执行被装饰的函数
            result = func(*args,**kwargs) 
            # 返回结果
            return result
        # 返回内层函数
        return wrapper
    

    普通--时间装饰器

    from functools import wraps
    import time
    from random import randint
    
    def use_time(func):
        @wraps(func)
        def wrapper(*args,**kwargs):
            st_time = time.time()
            result = func(*args,**kwargs)
            end_time = time.time()
            print(f'{func.__name__}函数use_time:{end_time-st_time}s')
        return wrapper
     
        
    @use_time
    def foo():
        time.sleep(randint(1,3))
    
    for _ in range(3):
        foo()
    
    #输出
    >>>>
    foo函数use_time:1.0007495880126953s
    foo函数use_time:3.0018675327301025s
    foo函数use_time:3.0030477046966553s
    

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

    • 可以发先上面时间装饰器计算的结果,只能在控制台上打印
    • 那我们怎样才能将它输出为日志呢???
    • 我们需要将他的结果进行自定输出
    # 在增加一层函数
    from functools import wraps
    import time
    from random import randint
    
    def record(output):
        def use_time(func):
            @wraps(func)
            def wrapper(*args,**kwargs):
                st_time = time.time()
                result = func(*args,**kwargs)
                end_time = time.time()
    #             print(f'{func.__name__}函数use_time:{end_time-st_time}s')
                output(func.__name__, end_time-st_time)
            return wrapper
        return use_time
    
    # 改装饰器的结果就可以自定义了,下面以print函数为例
    @record(print)
    def foo():
        time.sleep(randint(2,5))
    
    for _ in range(3):
        foo()
    >>>>
    foo 3.000645875930786
    foo 4.003818988800049
    foo 2.0020666122436523
    

    结果输出日志

    • 只需要自己定义一个函数
    def write_log(name,content):
        with open('./time.log','a')as f:
            f.write(f'{name}耗时:{content}\r\n') # \r\n 换行
            
    # 只需要将装饰器改为@record(write_log)
    @record(write_log)
    def foo():
        time.sleep(randint(2,5))
    
    for _ in range(3):
        foo()
    

    效果如下

    效果如图

    相关文章

      网友评论

          本文标题:对装饰器@wraps的解释(一看就懂)-- 并对装饰器浅谈

          本文链接:https://www.haomeiwen.com/subject/vmdziqtx.html