python functools update_wrapper,wraps使用

  • update_wrapper 使用

此函数主要用在装饰器函数中,装饰器返回函数反射得到的是包装函数的函数定义而不是原始函数定义

如下代码 整合 update_wrapper源码 和 示例代码在一个文件中,方便查看;

# -*- coding: utf-8 -*-
"""
(C) Guangcai Ren <rgc@bvrft.com>
All rights reserved
create time '2020/3/23 17:02'

Module usage:
functools.update_wrapper 使用方法
主要思路 是 被调用函数属性赋值给 内部函数
主要技术 setattr,getattr
"""

WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
                       '__annotations__')
WRAPPER_UPDATES = ('__dict__',)


def update_wrapper(wrapper,
                   wrapped,
                   assigned=WRAPPER_ASSIGNMENTS,
                   updated=WRAPPER_UPDATES):
    """Update a wrapper function to look like the wrapped function
        主要 把 wrapped 的 相关属性(WRAPPER_ASSIGNMENTS) 赋值给 wrapper 函数,并返回 wrapper 函数
       wrapper is the function to be updated:此参数为被赋值的函数, 返回值也是此参数
       wrapped is the original function:被装饰的函数
       assigned is a tuple naming the attributes assigned directly:被赋值的相关属性,默认为 WRAPPER_ASSIGNMENTS
       from the wrapped function to the wrapper function (defaults to
       functools.WRAPPER_ASSIGNMENTS)
       updated is a tuple naming the attributes of the wrapper that
       are updated with the corresponding attribute from the wrapped
       function (defaults to functools.WRAPPER_UPDATES)
    """
    for attr in assigned:
        try:
            value = getattr(wrapped, attr)
        except AttributeError:
            pass
        else:
            # 把 wrapped 的 相关属性(默认为WRAPPER_ASSIGNMENTS) 赋值给 wrapper 函数
            setattr(wrapper, attr, value)
    for attr in updated:
        getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
    # Issue #17482: set __wrapped__ last so we don't inadvertently copy it
    # from the wrapped function when updating __dict__
    wrapper.__wrapped__ = wrapped
    # Return the wrapper so this can be used as a decorator via partial()
    # 返回 带有 wrapped 的 相关属性 的 新 wrapper
    return wrapper


def wrap_fun(fun):
    def call_fun(*args, **kwargs):
        """
        内部调用函数,每次调用都不是被调用函数相关属性
        :param args:
        :param kwargs:
        :return:
        """
        print('print call fun')
        return fun(*args, **kwargs)

    # 此处直接返回 call_fun 的相关属性,导致 normal_fun.__name__获取的是 call_fun的相关属性
    return call_fun


@wrap_fun
def normal_fun():
    """
    一个普通函数
    :return:
    """
    print('print normal function')


def wrap_fun2(fun):
    """

    :param fun:
    :return:
    """

    def call_fun2(*args, **kwargs):
        """
        内部调用函数2
        :param args:
        :param kwargs:
        :return:
        """
        print('print call fun2')
        return fun(*args, **kwargs)

    # 把 被装饰的函数 fun=normal_fun2 的相关属性 赋值给 call_fun2函数,并且 wrap_fun2 返回值为 call_fun2,这样
    # 被装饰函数normal_fun2.__name__便是自己的名字

    return update_wrapper(call_fun2, fun)


@wrap_fun2
def normal_fun2():
    """
    成功进行属性赋值的函数
    :return:
    """
    print('print normal function2')


if __name__ == '__main__':
    print('未进行属性赋值情况')
    normal_fun()
    print(normal_fun.__name__)
    print(normal_fun.__doc__)

    print('进行属性赋值')
    normal_fun2()
    print(normal_fun2.__name__)
    print(normal_fun2.__doc__)

运行结果为:

  • wraps 使用

主要是对 上述 update_wrapper方法的封装,在开发中更加方便

源码为:


def wraps(wrapped,
          assigned = WRAPPER_ASSIGNMENTS,
          updated = WRAPPER_UPDATES):
    """Decorator factory to apply update_wrapper() to a wrapper function

       Returns a decorator that invokes update_wrapper() with the decorated
       function as the wrapper argument and the arguments to wraps() as the
       remaining arguments. Default arguments are as for update_wrapper().
       This is a convenience function to simplify applying partial() to
       update_wrapper().
    """
    return partial(update_wrapper, wrapped=wrapped,
                   assigned=assigned, updated=updated)

所以@wraps的等价形式如下:
wrapper = partial(update_wrapper, wrapped=func, assigned=assigned, updated=updated)(wrapper)
进一步等价:
wrapper = update_wrapper(wrapper=wrapper, wrapped=func, assigned=assigned, updated=updated)

关于 partial 的理解如下链接:xxx

示例代码:


from functools import wraps


def wrap_fun3(fun):
    """

    :param fun:
    :return:
    """

    @wraps(fun)
    def call_fun3(*args, **kwargs):
        """
        内部调用函数3
        :param args:
        :param kwargs:
        :return:
        """
        print('print call fun3')
        return fun(*args, **kwargs)

    return call_fun3


@wrap_fun3
def normal_fun3():
    """
    成功使用wrpas进行属性赋值的函数
    :return:
    """
    print('print normal function3')


if __name__ == '__main__':
    print('使用wraps进行属性赋值')
    normal_fun3()
    print(normal_fun3.__name__)
    print(normal_fun3.__doc__)

结果如下:

 

相关链接:

http://blog.chinaunix.net/uid-8599612-id-3012687.html

https://www.sohu.com/a/331923444_571478

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值