美文网首页
python装饰器functools wraps

python装饰器functools wraps

作者: bonnie_xing | 来源:发表于2019-07-19 16:24 被阅读0次

    引自:https://www.cnblogs.com/myd7349/p/how_to_use_wraps_of_functools.html

    一、wraps装饰器使用

    1、通过trace装饰器,打印函数调用内容(未使用wraps)

    # coding: utf-8
    # Filename: decorator_wraps_test.py
    import sys
    
    debug_log = sys.stderr
    
    def trace(func):
        if debug_log:
            def callf(*args, **kwargs):
                """A wrapper function."""
                debug_log.write('Calling function: {}\n'.format(func.__name__))
                res = func(*args, **kwargs)
                debug_log.write('Return value: {}\n'.format(res))
                return res
            return callf
        else:
            return func
    
    @trace
    def square(x):
        """Calculate the square of the given number."""
        return x * x
    
    if __name__ == '__main__':
        print(square(3))
    
    输出:
    Calling function: square
    Return value: 9
    9
    

    2、查看实际调用函数的内容

    if __name__ == '__main__':
        help(square)
        print(square.__name__)
        print('debug_log' in square.__globals__)
        print('sys' in square.__globals__)
    
    输出
    callf(*args, **kwargs)
        A wrapper function.
    
    callf
    True
    True
    

    与预期不一致,期待返回的是square函数的信息
    实际返回的是装饰器trace返回的callf函数信息

    如何解决这个问题呢,那么就需要使用functools的wraps

    3、通过wraps实现,展示真实的函数调用

    # coding: utf-8
    # Filename: decorator_wraps_test.py
    import functools
    import sys
    
    debug_log = sys.stderr
    
    def trace(func):
        if debug_log:
            @functools.wraps(func)
            def callf(*args, **kwargs):
                """A wrapper function."""
                debug_log.write('Calling function: {}\n'.format(func.__name__))
                res = func(*args, **kwargs)
                debug_log.write('Return value: {}\n'.format(res))
                return res
            return callf
        else:
            return func
    
    @trace
    def square(x):
        """Calculate the square of the given number."""
        return x * x
    
    if __name__ == '__main__':
        print(square(3))
        print(square.__doc__)
        print(square.__name__)
        print('debug_log' in square.__globals__)
        print('sys' in square.__globals__)
    
    输出
    Calling function: square
    Return value: 9
    9
    Calculate the square of the given number.
    square
    True
    True
    

    通过functools的wraps实现了在获取“square.name”信息时,输出的是square

    二、引申:wraps装饰器分析

    对代码要求较高,比较感兴趣的话,可以了解下

    1、带参数的装饰器

    def trace(log_level):
        def impl_f(func):
            print(log_level, 'Implementing function: "{}"'.format(func.__name__))
            return func
        return impl_f
    
    
    @trace('[INFO]')
    def print_msg(msg):
        print(msg)
    
    
    @trace('[DEBUG]')
    def assert_(expr):
        assert expr
    
    print_msg('Hello, world!')
    
    输出
    [INFO] Implementing function: "print_msg"
    [DEBUG] Implementing function: "assert_"
    Hello, world!
    

    装饰器理解

    @trace('[INFO]')
    def print_msg(msg): print(msg)
    

    等价于

    temp = trace('[INFO]')
    def _print_msg(msg): print(msg)
    print_msg = temp(_print_msg)
    

    2、partial函数

    # coding: utf-8
    from functools import partial
    
    
    def foo(x, y, z):
        print(locals())
    
    foo(1, 2, 3)
    
    foo_without_z = partial(foo, z = 100)
    foo_without_z
    
    foo_without_z is foo
    
    foo_without_z(10, 20)
    
    输出:
    {'z': 3, 'y': 2, 'x': 1}
    {'z': 100, 'y': 20, 'x': 10}
    

    说明:
    我们通过partial为foo提供参数z的值,得到了一个新的“函数对象”
    foo_without_z和一般的函数对象有些差别。比如,foo_without_z没有name属性
    文档字符串doc也和partial的文档字符串很相像

    foo_without_z(10, 20)
    
    等价于
    
    foo(10, 20, z = 100)
    

    相关文章

      网友评论

          本文标题:python装饰器functools wraps

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