学习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新手,如有错漏,还请指教。