Python 装饰器

装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

 1 import time
 2  
 3 def show_time(func):
 4     def wrapper():
 5         start_time=time.time()
 6         func()
 7         end_time=time.time()
 8         print('spend %s'%(end_time-start_time))
 9  
10     return wrapper
11  
12  
13 def foo():
14     print('hello foo')
15     time.sleep(3)
16  
17 foo=show_time(foo)
18 foo()

函数show_time就是装饰器,它把真正的业务方法func包裹在函数里面,看起来像foo被上下时间函数装饰了。在这个例子中,函数进入和退出时 ,被称为一个横切面(Aspect),这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。 

@符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作

 1 import time
 2  
 3 def show_time(func):
 4     def wrapper():
 5         start_time=time.time()
 6         func()
 7         end_time=time.time()
 8         print('spend %s'%(end_time-start_time))
 9  
10     return wrapper
11  
12 @show_time   #foo=show_time(foo)
13 def foo():
14     print('hello foo')
15     time.sleep(3)
16  
17  
18 @show_time  #bar=show_time(bar)
19 def bar():
20     print('in the bar')
21     time.sleep(2)
22  
23 foo()
24 print('***********')
25 bar()

装饰器在Python使用如此方便都要归因于Python的函数能像普通的对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。

带参数的被修饰函数

 1 import time
 2  
 3 def show_time(func):
 4  
 5     def wrapper(a,b):
 6         start_time=time.time()
 7         func(a,b)
 8         end_time=time.time()
 9         print('spend %s'%(end_time-start_time))
10  
11     return wrapper
12  
13 @show_time   #add=show_time(add)
14 def add(a,b):
15  
16     time.sleep(1)
17     print(a+b)
18  
19 add(2,4)

装饰器带参数

import time
 
def time_logger(flag=0):
 
    def show_time(func):
 
            def wrapper(*args,**kwargs):
                start_time=time.time()
                func(*args,**kwargs)
                end_time=time.time()
                print('spend %s'%(end_time-start_time))
 
                if flag:
                    print('将这个操作的时间记录到日志中')
 
            return wrapper
 
    return show_time
 
 
@time_logger(3)    # add = time_loger(3)(add)
def add(*args,**kwargs):
    time.sleep(1)
    sum=0
    for i in args:
        sum+=i
    print(sum)
 
add(2,7,5)

 

-------------------------------------------------------

补全

 

import time


def cal_time(func):

    def inter(*args, **kwargs):
        t1 = time.time()
        result = func(*args, **kwargs)
        t2 = time.time()
        print("%s time: %s" % (func.__name__, t2 - t1))
        return result

    return inter


@cal_time
def add(x, y):
    return x + y

当使用一个装饰器时,打印函数名会出现问题

print(add.__name__)
##输出
inter

使用标准库里的functools.wraps,可以基本解决这个问题

看的别人写的文章说是拿不到数字签名等信息,但是在Python3.5里面可以拿到

可以使用wrapt包来进行修正

Wrapt

需要安装

pip install wrapt

wrapt是一个功能非常完善的包,用于实现各种你想到或者你没想到的装饰器。使用wrapt实现的装饰器你不需要担心之前inspect中遇到的所有问题,因为它都帮你处理了,甚至inspect.getsource(func)也准确无误。

import wrapt


@wrapt.decorator
def cal_time(func, instance, args, kwargs):
    t1 = time.time()
    result = func(*args, **kwargs)
    t2 = time.time()
    print("%s time: %s" % (func.__name__, t2 - t1))
    return result


@cal_time
def add(x, y):
    return x + y

使用wrapt你只需要定义一个装饰器函数,但是函数签名是固定的,必须是(wrapped, instance, args, kwargs),注意第二个参数instance是必须的,就算你不用它。当装饰器装饰在不同位置时它将得到不同的值,比如装饰在类实例方法时你可以拿到这个类实例。根据instance的值你能够更加灵活的调整你的装饰器。另外,argskwargs也是固定的,注意前面没有星号。在装饰器内部调用原函数时才带星号。

如果你需要使用wrapt写一个带参数的装饰器,可以这样写。

  

  

  

 

转载于:https://www.cnblogs.com/bw13/p/5850367.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值