对Python中带参数装饰器的理解

学习Python的装饰器时,在装饰器的参数这里卡住了,后来总算是搞清楚了怎么回事。

为了方便起见,这里只讨论由函数定义的函数装饰器。

普通的无参数装饰器很好理解:

def dec1(F):
    def wrapper(*args):
        F(*args)
    return wrapper

@dec1
def spam(a, b, c):
    print(a + b + c)

# 实际的效果是:
# spam = dec1(spam)

通过自动重绑定,变量spam被重新赋值为另一个函数对象,这个函数对象是dec函数的返回值,即wrapper函数。

装饰器的语法就是简化了像注释中那样的赋值,即将spam函数对象作为参数传入dec函数,然后将返回值重新赋值给spam变量。

下面来看带参数的情况:

# 为了方便对照,这里参数的变量名是类似的,其实没有必要
# 后面会给出一个变量名更好看的例子
def dec2(F):
    def wrapper(*args):
        return *args
    return wrapper

@dec2('anything')
def spam(a, b, c):
    print(a + b + c)

这个例子看起来跟上个例子差不多,只不过在@装饰器的时候多加了一个参数,但其实是有很大不同的。

如果继续套用装饰器自动重绑定的定义,就会发现问题:

由于已经有了一个参数,spam该怎么传给dec函数?

难道是spam = dec('anything', spam)?

根据dec的定义,它只能接受一个参数,这样显然是不对的。

从另一个角度看,我们可以认为@装饰器语法最终是不能接受显式参数的,唯一的隐式参数只能是它修饰的函数对象。

为了符合这个要求,dec('anything')就必须在装饰spam之前完成调用,并由其返回值wrapper完成对spam的装饰。实际的效果就是这样的:

wrapper = dec2('anything')
# 由上面的定义可以知道,wrapper没有进行任何动作,直接返回了spam函数对象
@wrapper
def spam(a, b, c):
    print(a + b + c)
# 这里可以看到,wrapper函数其实最终只会接受一个参数,并不需要*args

为了更好看,我们重写dec函数:

# dec3函数可以接受一个显式参数,并返回实际的装饰器
def dec3(value):
    # decorator才是实际生效的装饰器
    def decorator(F):
        def wrapper(*args):
            F(*args)
        return wrapper
    return decorator

@dec3('anything')
def spam(a, b, c):
    print(a + b + c)
'''
实际的效果是:
decorator = dec3('anything')
@decorator
def spam(a, b, c):
    print(a + b + c)
'''

# Python新手,如有错漏,还请指教。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值