从本质上分析装饰器
正规写法:
import time def timeslong(func): def call(): start = time.clock() print("It's time starting ! ") func() print("It's time ending ! ") end = time.clock() return "It's used : %s ." % (end - start) return call @timeslong def f(): y = 0 for i in range(10): y = y + i + 1 print(y) return y print(f())
等价写法:
import time def timeslong(func): def call(): start = time.clock() print("It's time starting ! ") func() print("It's time ending ! ") end = time.clock() return "It's used : %s ." % (end - start) return call def f(): y = 0 for i in range(10): y = y + i + 1 print(y) return y f = timeslong(f) print(f())
错误写法:
import time def timeslong(func): start = time.clock() print("It's time starting ! ") func() print("It's time ending ! ") end = time.clock() return "It's used : %s ." % (end - start) @timeslong def f(): y = 0 for i in range(10): y = y + i + 1 print(y) return y f() //-----------报错信息: Traceback (most recent call last): File "E:/python_pri/Fishc40.py", line 100, in <module> f() TypeError: 'str' object is not callable
如果timeslong并不是一个返回函数便签的高阶函数,那么就会报这个错误!
如果说f()的实现过程就是将f作为参数传入timeslong(),这样不应该报错,如:
timeslong(f),这样不仅不报错,而且实现同样的功能!
那,上面报错的原因是什么呢?我们得从本质上分析:
@timeslong
def f():
pass
上面这段代码等价于,下面这段代码:
def f():
pass
f = timeslong(f)
现在同名的f变量指向了新的函数,于是调用f()将执行新函数——timeslong(f)。
那么,有鱼油就问了,既然f都赋了新的值,那么为什么timeslong(f)中的f调用的还是之前的f函数呢?
这个问题问的好:
原因是,f = timeslong(f)在执行的过程中,按照顺序先执行timeslong(f),再赋值f。在timeslong(f)这个过程中
,之前的f已经被保存到了timeslong函数的内部变量func中,当再次调用的f()的时候timeslong(f)中的是之前的f函数内容。
所以确切的说: @timeslong 等价于 f = timeslong(func)。才更为准确。
所以f()就等价于timeslong(func)()
再来说报错问题,就很明显了,如果timeslong不是一个高阶函数,按照上面的写法,timeslong返回的是一个
字符串,那么最终的结果可以看成:
f = timeslong(f) = 'str'
'str'()
字符串当然不会被调用,所以报错:
TypeError: 'str' object is not callable
作者:宋桓公
出处:http://www.cnblogs.com/douzi2/
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。