• python笔记36-装饰器之wraps


    前言

    前面一篇对python装饰器有了初步的了解了,但是还不够完美,领导看了后又提出了新的需求,希望运行的日志能显示出具体运行的哪个函数。

    name__和__doc

    __name__用于获取函数的名称,__doc__用于获取函数的docstring内容(函数的注释)

    import time
    
    def func_a(a):
        '''func_a --> hello'''
        print("hello"+a)
        time.sleep(0.5)
        return True
    
    
    def func_b(b, c="xx"):
        '''func_b --> world'''
        print("world"+b+c)
        time.sleep(0.8)
        return True
    
    if __name__ == '__main__':
        print(func_a.__name__)  # 结果 func_a
        print(func_a.__doc__)   # func_a --> hello
        print(func_b.__name__)  # func_b
        print(func_b.__doc__)   # func_b --> world
    

    装饰器加函数名称日志

    在装饰器里面添加2行代码,打印正在运行函数的名称和docstring内容

    import time
    
    
    def runtime(func):
        '''runtime decorators'''
        def wrapper(*args, **kwargs):
            '''wrapper inner fuction'''
            print("running function : %s" % func.__name__)   
            print("docstring: %s" % func.__doc__)
            start = time.time()
            f = func(*args, **kwargs)     # 原函数
            end = time.time()
            print("运行时长:%.4f 秒" % (end-start))
            return f
        return wrapper
    
    
    @runtime
    def func_a(a):
        '''func_a --> hello'''
        print("hello"+a)
        time.sleep(0.5)
        return True
    
    
    @runtime
    def func_b(b, c="xx"):
        '''func_b --> world'''
        print("world"+b+c)
        time.sleep(0.8)
        return True
    
    if __name__ == '__main__':
        func_a("a")
        print(func_a.__name__)
        print(func_a.__doc__)
    

    运行结果

    running function : func_a
    docstring: func_a --> hello
    helloa
    运行时长:0.5008 秒
    wrapper
    wrapper inner fuction
    

    从运行的结果可以看出,func_a.__name__运行的结果是wrapper, func_a.__doc__运行的结果是wrapper inner fuction。
    也就是说被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),那这个问题如何解决呢?
    这就需要用到functools里面的一个wraps函数了

    functools

    当func_a函数被装饰后,导致了一个副作用:自身的函数属性和docstring内容变成了wrapper函数的属性了。
    这里需用到functools里面的一个wraps的装饰器来消除这样的副作用。

    import time
    from functools import wraps
    
    def runtime(func):
        '''runtime decorators'''
        @wraps(func)
        def wrapper(*args, **kwargs):
            '''wrapper inner fuction'''
            print("running function : %s" % func.__name__)
            print("docstring: %s" % func.__doc__)
            start = time.time()
            f = func(*args, **kwargs)     # 原函数
            end = time.time()
            print("运行时长:%.4f 秒" % (end-start))
            return f
        return wrapper
    
    

    只需在wrapper函数上加上@wraps(func)即可解决

    运行结果

    running function : func_a
    docstring: func_a --> hello
    helloa
    运行时长:0.5004 秒
    func_a
    func_a --> hello
    

    类装饰器

    带参数的装饰器,可以写成类装饰器

    import time
    from functools import wraps
    
    class runtime(object):
        '''runtime class decorators'''
        def __init__(self, slowly=1):
            self.slowly = slowly
    
        def __call__(self, func):
            @wraps(func)
            def wrapper(*args, **kwargs):
                '''wrapper inner fuction'''
                print("running function : %s" % func.__name__)
                print("docstring: %s" % func.__doc__)
                start = time.time()
                f = func(*args, **kwargs)     # 原函数
                end = time.time()
                t = end-start
                time.sleep((self.slowly-1)*t)  # 延迟效果
                new_end = time.time()
                print("运行时长:%.4f 秒" % (new_end-start))
                return f
            return wrapper
    
    
    @runtime(1.5)
    def func_a(a):
        '''func_a --> hello'''
        print("hello"+a)
        time.sleep(0.5)
        return True
    
    
    @runtime()
    def func_b(b, c="xx"):
        '''func_b --> world'''
        print("world"+b+c)
        time.sleep(0.8)
        return True
    
    if __name__ == '__main__':
        func_a("a")
        print(func_a.__name__)
        print(func_a.__doc__)
    
    

    运行结果

    running function : func_a
    docstring: func_a --> hello
    helloa
    运行时长:0.7522 秒
    func_a
    func_a --> hello
    

    python自动化交流 QQ群:779429633

  • 相关阅读:
    人类登月不可或缺 大型机半个世纪发展史
    宽带上网知识(如何进行上网流程配置,路由器上网配置)
    团队项目第二阶段——第二天
    用户体验评价之QQ浏览器
    团队项目第二阶段——第一天
    第十四周学习进度总结
    《梦断代码》阅读笔记02
    第十三周学习进度总结
    第一阶段意见评论
    第十二周学习进度总结
  • 原文地址:https://www.cnblogs.com/yoyoketang/p/10803575.html
Copyright © 2020-2023  润新知