AI智能
改变未来

python进阶(18)@wraps装饰器


前言

我们都知道装饰器的作用是在不改变原有的代码基础上,添加新的功能,但是这样会有一个弊端,被装饰的函数某些属性会变改变,接下来我们来看下

案例

import timedef run_time(func):def wrapper(*args, **kwargs):\"\"\"时间装饰器\"\"\"time1 = time.time()func(*args, **kwargs)time2 = time.time()cost_time = time2 - time1return f\"函数花了{cost_time}秒\"return wrapper@run_timedef test():\"\"\"测试\"\"\"print([i for i in range(1, 100001) if i % 200 == 0])if __name__ == \'__main__\':print(test.__name__)print(test.__doc__)\"\"\"结果# wrapper# 时间装饰器\"\"\"

可以看到,我们明明打印的是test函数的

__name__

属性,最后显示的却是

run_time

的属性。

我们知道

@run_time

装饰器实际上就等于

test = run_time(test)

,此时我们打印

test.__name__

实际上test已经指向了

wrapper

,这样会造成我们打印的时候会打印装饰器的内嵌函数的名字和注释。

使用wraps装饰器解决

wraps

可以将原函数对象的指定属性复制给包装函数对象, 默认有

__module__

__name__

__doc__

__qualname__

__annotations__

或者通过参数选择

import timefrom functools import wrapsdef run_time(func):@wraps(func)def wrapper(*args, **kwargs):\"\"\"时间装饰器\"\"\"time1 = time.time()func(*args, **kwargs)time2 = time.time()cost_time = time2 - time1return f\"函数花了{cost_time}秒\"return wrapper@run_timedef test():\"\"\"测试\"\"\"print([i for i in range(1, 100001) if i % 200 == 0])if __name__ == \'__main__\':print(test.__name__)print(test.__doc__)\"\"\"结果:test测试\"\"\"

我们就只在原来的

wrapper

内函数上加了一个

@wraps(func)

装饰器,就可以打印出我们想要的结果了,这是因为

wraps

可以将原函数对象的指定属性复制给包装函数对象,我们可以查看它的源码

def wraps(wrapped,assigned = WRAPPER_ASSIGNMENTS,updated = WRAPPER_UPDATES):\"\"\"Decorator factory to apply update_wrapper() to a wrapper functionReturns a decorator that invokes update_wrapper() with the decoratedfunction as the wrapper argument and the arguments to wraps() as theremaining arguments. Default arguments are as for update_wrapper().This is a convenience function to simplify applying partial() toupdate_wrapper().\"\"\"return partial(update_wrapper, wrapped=wrapped,assigned=assigned, updated=updated)
赞(0) 打赏
未经允许不得转载:爱站程序员基地 » python进阶(18)@wraps装饰器