从本质上分析装饰器

正规写法:

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

posted @ 2016-06-13 15:14  宋桓公  阅读(268)  评论(0编辑  收藏  举报