python中编写无参数decorator
Python的 decorator 本质上就是一个高阶函数,它接收一个函数作为参数,然后,返回一个新函数。
使用 decorator 用Python提供的 @ 语法,这样可以避免手动编写f = decorate(f) 这样的代码。
考察一个@log的定义:
1 def log(f):#编写一个装饰器,本质就是一个高阶函数,接受一个函数(f)作为参数,然后返回一个新函数fn 2 def fn(x): 3 print 'call ' + f.__name__ + '()...'#实现打印函数调用 4 return f(x)#返回一个函数,对于f(x),只有一个参数x 5 return fn#返回一个新函数
对于阶乘函数,@log工作得很好:
1 @log 2 def factorial(n): 3 return reduce(lambda x,y: x*y, range(1, n+1)) 4 print factorial(10)
结果:
call factorial()... 3628800
但是,对于参数不是一个的函数,调用将报错:
@log def add(x, y): return x + y print add(1, 2)
结果:
1 Traceback (most recent call last): 2 File "test.py", line 15, in <module> 3 print add(1,2) 4 TypeError: fn() takes exactly 1 argument (2 given)
因为 add() 函数需要传入两个参数,但是 @log 写死了只含一个参数的返回函数。
要让 @log 自适应任何参数定义的函数,可以利用Python的 *args 和 **kw,保证任意个数的参数总是能正常调用:
1 def log(f): 2 def fn(*args, **kw): 3 print 'call ' + f.__name__ + '()...' 4 return f(*args, **kw) 5 return fn
任务
请编写一个@performance,它可以打印出函数调用的时间。
1 import time 2 3 def performance(f):#编写一个时间装饰器,用来打印调用函数的时间 4 def fn(*args,**kw):#自适应任何参数定义,保证了任意个数的参数总是能正常调用 5 t1 = time.time()#调用前计时 6 r = f(*args,**kw)#这里f是要调用的那个函数 7 t2 = time.time()#调用完计时 8 print 'call %s() in %fs' %(f.__name__, (t2-t1)) 9 return r#返回函数 10 return fn#返回新的函数fn 11 12 13 @performance 14 def factorial(n): 15 return reduce(lambda x,y: x*y, range(1, n+1)) 16 17 print factorial(10)