关于装饰器的副作用
装饰器不是这样起作用的吗:f = log(f),为什么函数名还会被修改?
装饰器不是这样起作用的吗:f = log(f),为什么函数名还会被修改?
2015-10-25
我自己的理解:
1.以上面的log函数为例,log内部定义了fn函数,fn.__name__ 为 'fn'
def log(f): def fn(x): print 'call ' + f.__name__ + '()...' return f(x) return fn
当执行了f = log(f),因为log函数返回的也是一个函数(fn),所以f实际指向的函数(fn),f.__name__ 为 'fn'
你可以试下: f=log,此时,f指向的函数就是(log),f.__name__ 为 'log'
2.再进一步,以本题答案为例:
def performance(unit): def perf_decorator(f): @functools.wraps(f) def wrapper(*args, **kw): t1 = time.time() r = f(*args, **kw) t2 = time.time() t = (t2-t1)*1000 if unit == 'ms' else t2-t1 print 'call %s() in %f %s'%(f.__name__,t,unit) return r return wrapper return perf_decorator
本质是 f = performance(unit)(f)
performance(unit) 返回 perf_decorator 函数,perf_decorator(f) 返回 wrapper函数,所以f指向wrapper函数,如果不加装饰器@functools.wraps(f),则f.__name__ 为 'wrapper'。
加了@functools.wraps(f)之后,functools.wraps函数会执行 wrapper.__name__ = f.__name__
所以最终f.__name__ 的值仍为'f',有点绕,这是我自己的理解。
3.你可以在编写带参数的那章执行如下代码看看:
# -*- coding: utf-8 -*- import time def performance(unit): def perf_decorator(f): def wrapper(*args, **kw): t1 = time.time() r = f(*args, **kw) t2 = time.time() t = (t2-t1)*1000 if unit == 'ms' else t2-t1 print 'call %s() in %f %s'%(f.__name__,t,unit) return r return wrapper return perf_decorator #@performance('ms') 不用装饰器 def factorial(n): return reduce(lambda x,y: x*y, range(1, n+1)) #手动装饰 factorial = performance('ms')(factorial) print factorial(10) print factorial.__name__
举报