装饰器(二)

上一篇装饰器(一)讲解了装饰器的基本用法,这篇我们来看一下装饰器的进阶用法。

一. 同一个函数调用多个装饰器

如果一个函数被多个装饰器装饰,也就是这个函数需要添加很多的功能,应该如何写呢?

import time

def get_time(foo):
    def inner():
        starttime = time.time()
        foo()
        endtime = time.time()
        print("func2执行了%s秒" % (endtime - starttime))
    return inner

def log(foo):
    def inner():
        print("%s执行了"%foo.__name__)
        foo()
    return inner

@log
@get_time
def func2():
    print("我在执行func2")

func2()

执行结果为
在这里插入图片描述
我们来对这个调用顺序进行讲解:
对于装饰器的调用,离函数定义越近的装饰器越先调用。也就是先调用get_time,再调用log。那么
@get_time就等价于func2 = get_name(func2),返回了inner,一定要注意,这个时候inner并未执行!
@log等价于func2 = log(func2),也就是func2 = log(get_name(func2)),即func2 = log(inner)

二. 被调用函数有参数

def log(foo):
    def inner():
        print("%s执行了"%foo.__name__)
        foo()
    return inner

@log    #func2(arg)=log(func2)(f2)
def func2(test):
    print(test)

func2("我是func2")

如果被修饰函数func2有了参数,还是按之前的调用方式,是会报错的
在这里插入图片描述
报错原因在于,inner没有参数,那么可能会想,只要在inner加一个参数就好了嘛,但是这仅仅是满足了单个参数函数的需要,如果两个参数的函数,难道需要重写装饰器?这显然是不现实的,那Python给我们提供了一个函数的动态参数inner(*args,**kwargs)就可以不管被修饰函数的参数如何,都可以使用这一个装饰器。

def log(foo):
    def inner(*args,**kwargs):
        print("%s执行了"%foo.__name__)
        foo(*args,**kwargs)
    return inner

@log
def func2(test):
    print(test)

func2("我是func2")

三. 装饰器完整模板

def log(foo):
    def inner(*args,**kwargs):
        print("%s执行了"%foo.__name__)
        foo(*args,**kwargs)
    return inner
    
@log
def func3(x,y):
    return x+y

res = func3(2,3)
print(res)

对于上述代码我们执行后发现没有接收到func3的返回值
在这里插入图片描述
为什么呢?因为@log等价于fun3=log(fun3),到了装饰器函数发现,inner的确是没有返回值,那我们定义一个res来接受返回值再给它返回出去就好。我们这样改就可以了,接下来的装饰器便是完整的一个模板。

def log(foo):
    def inner(*args,**kwargs):
        print("%s执行了"%foo.__name__)
        res = foo(*args,**kwargs)
        return res
    return inner

@log
def func3(x,y):
    return x+y

res = func3(2,3)
print(res)

四. warps的使用

在实践中可能会出现这样的问题,被装饰器装饰的函数已经不是原来的那个函数了,如果我们想看一看原来函数里面的内容(例如注释)应该怎么办呢?

def deco(func):
    def wrapper(*args,**kwargs):
        return func(*args,**kwargs)
    return wrapper
@deco
def index():
    "注释"
    print('from index')

print(index.__doc__)    #它得不到注释的内容,因为index已经不是原来的函数了

解决这样的问题,我们只要使用wraps模块就可以解决了,并且在装饰器中添加@warps,就可以保留原来的函数里面的内容了。

from functools import wraps

def deco(func):
    @wraps(func)
    def wrapper(*args,**kwargs):
        return func(*args,**kwargs)
    return wrapper
@deco
def index():
    "注释"
    print('from index')

print(index.__doc__)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值