- 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__)
结果如下:
相关链接: