修饰带参数的参数
上两篇提到的装饰器的例子中,被修饰的函数没有参数,那么如果修饰带参数的装饰器又该如何书写呢?
#coding=utf-8
def f1(func):
print('in f1')
def f1_inner():
print('in f1_inner')
func()
return f1_inner
@f1
def f(a,b):
print('in f')
if __name__ == '__main__':
a,b = 1,2
f(a,b)
结果:
in f1
Traceback (most recent call last):
File "E:/sourceInsightPro/python_code/16点14分/zhuangshiqi2.py", line 16, in <module>
f(a,b)
TypeError: f_inner() takes 0 positional arguments but 2 were given
首先f在定义是需要两个参数,因此在调用的时候传入两个参数,但是结果却报错,提示16行错误:f_inner()不需要位置参数却传给了两个参数。
原因是装饰器f1修饰函数f,利用闭包的语句实现就是:f = f1(f),这句执行后f1返回的是f1_inner的引用,而f本身传入了两个参数,f1_inner在定义时却没有参数,因此才出现了这个错误,因此,在f1_inner定义时需要定义形参。即代码如下所示:
def f1(func):
print('in f1')
def f1_inner(a,b):
print('in f1_inner')
func()
return f1_inner
@f1
def f(a,b):
print('in f')
if __name__ == '__main__':
a,b = 1,2
f(a,b)
结果:
in f1
Traceback (most recent call last):
in f1_inner
File "E:/sourceInsightPro/python_code/16点14分/zhuangshiqi2.py", line 16, in <module>
f(a,b)
File "E:/sourceInsightPro/python_code/16点14分/zhuangshiqi2.py", line 7, in f_inner
func()
TypeError: f() missing 2 required positional arguments: 'a' and 'b'
在f1_inner中加上形参后发现依旧报错,提示是第六行:函数f丢了两个位置参数。
原因是在调用函数f(a,b)后,f是作为实参传入f1中,但是在f1_inner中调用func(即f)时却没有传入参数,因此才出现了这样的错,修改后的完整代码如下:
#coding=utf-8
def f1(func):
print('in f1')
def f1_inner(a,b):
print('in f1_inner,a:%d b:%d' % (a,b))
func(a,b)
return f1_inner
@f1
def f(a,b):
print('in f')
print('a:%d b:%d' % (a,b))
if __name__ == '__main__':
a,b = 1,2
f(a,b)
结果:
in f1
in f1_inner,a:1 b:2
in f
a:1 b:2
至此实现了装饰器修饰带参数的函数。但是却引入一个问题:上面例子中f需要两个参数,因此在f1_inner定义时也声明了两个形参。但是这样的书写形式太麻烦,耦合性太大,能否换一种简便的书写形式呢?此时便可以使用之前函数中的学到的:*args和**kwargs。看下面的代码:
def f2(func):
print('in f2')
def f2_inner(*args,**kwargs):
print('in f2_inner')
print(args)
print(kwargs)
func(*args,**kwargs)
return f2_inner
@f2
def f(a,b,*args,**kwargs):
print('in f')
print(a)
print(b)
print(args)
print(kwargs)
if __name__ == '__main__':
a,b = 1,2
f(a,b,'hello','world',c = 10,d = 20)
结果:
in f2
in f2_inner
(1, 2, 'hello', 'world')
{'c': 10, 'd': 20}
in f
1
2
('hello', 'world')
{'c': 10, 'd': 20}