对装饰器@wraps的解释(一看就懂)-- 并对装饰器详解

1. 先看一段代码

def is_login(func):
    def foo(*args,**kwargs):
        return func(*args,**kwargs)
    return foo

def test():
    print('我是:',test.__name__)

@is_login
def test1():
    print('我是:',test1.__name__)
@is_login
def test2():
    print('我是:',test2.__name__)
    
test()
test1()
test2()

>>>>

我是: test
我是: foo
我是: foo

可以发现函数的函数名即 name已被装饰器改变

2.那我们来增加@wraps

from functools import wraps

def is_login(func):
    @wraps(func)
    def foo(*args,**kwargs):
        return func(*args,**kwargs)
    return foo

def test():
    print('我是:',test.__name__)

@is_login
def test1():
    print('我是:',test1.__name__)
@is_login
def test2():
    print('我是:',test2.__name__)
    
test()
test1()
test2()

>>>>
我是: test
我是: test1
我是: test2

结论:

可以看见@wraps可以保证装饰器修饰的函数的name的值保持不变


补充:装饰的优化

以时间装饰器为例,进行优化

  • 装饰器的统一模板
from functools import wraps
# 对函数的装饰器, 对类func最好为cls
def decorate(func):
    @wraps(func)
    # 增添或修改功能的函数
    def wrapper(*args,**kwargs):
                # 执行被装饰的函数
        result = func(*args,**kwargs) 
        # 返回结果
        return result
    # 返回内层函数
    return wrapper

普通--时间装饰器

from functools import wraps
import time
from random import randint

def use_time(func):
    @wraps(func)
    def wrapper(*args,**kwargs):
        st_time = time.time()
        result = func(*args,**kwargs)
        end_time = time.time()
        print(f'{func.__name__}函数use_time:{end_time-st_time}s')
    return wrapper
 
    
@use_time
def foo():
    time.sleep(randint(1,3))

for _ in range(3):
    foo()

#输出
>>>>
foo函数use_time:1.0007495880126953s
foo函数use_time:3.0018675327301025s
foo函数use_time:3.0030477046966553s

下面对改装饰器进行优化(解耦)

  • 可以发先上面时间装饰器计算的结果,只能在控制台上打印
  • 那我们怎样才能将它输出为日志呢???
  • 我们需要将他的结果进行自定输出
# 在增加一层函数
from functools import wraps
import time
from random import randint

def record(output):
    def use_time(func):
        @wraps(func)
        def wrapper(*args,**kwargs):
            st_time = time.time()
            result = func(*args,**kwargs)
            end_time = time.time()
#             print(f'{func.__name__}函数use_time:{end_time-st_time}s')
            output(func.__name__, end_time-st_time)
        return wrapper
    return use_time

# 改装饰器的结果就可以自定义了,下面以print函数为例
@record(print)
def foo():
    time.sleep(randint(2,5))

for _ in range(3):
    foo()
>>>>
foo 3.000645875930786
foo 4.003818988800049
foo 2.0020666122436523

结果输出日志

  • 只需要自己定义一个函数
def write_log(name,content):
    with open('./time.log','a')as f:
        f.write(f'{name}耗时:{content}\r\n') # \r\n 换行
        
# 只需要将装饰器改为@record(write_log)
@record(write_log)
def foo():
    time.sleep(randint(2,5))

for _ in range(3):
    foo()

效果如下

 
效果如图


作者:憧憬001
链接:https://www.jianshu.com/p/5df1769e562e
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
posted @ 2019-07-27 09:47  交流_QQ_2240410488  阅读(3723)  评论(0编辑  收藏  举报