Python装饰器真的只是语法糖吗?

经常用Python的人对装饰器(decorator)应该不陌生。装饰器本质上只是个语法糖,理解起来很容易。官方文档对其的解释为:

The decorator syntax is merely syntactic sugar, the following two function definitions are semantically equivalent:

def f(...):
    ...
f = staticmethod(f)

@staticmethod
def f(...):
    ...

然而,这两种写法真的在任何情况下都等价吗?看一个例子:

import timeit
import time

def timer(func):
    ret = timeit.timeit(stmt = func.__name__ + '()',
        setup = "from " + func.__module__ + " import " + func.__name__,
        number = 1)
    print "Execution time of %s: %.2fs" % (func.__name__, ret)

def foo():
    time.sleep(0.1)

timer(foo)

函数timer旨在测量函数的执行时间。它利用了Python自带的计时模块timeit。注意当需要在timeit中执行函数的时候,需要先导入函数,此处导入方式是from __main__ import foo
执行结果:
Execution time of foo: 0.10s

如果把timer用作装饰器呢?

import timeit
import time

def timer(func):
    ret = timeit.timeit(stmt = func.__name__ + '()',
        setup = "from " + func.__module__ + " import " + func.__name__,
        number = 1)
    print "Execution time of %s: %.2fs" % (func.__name__, ret)
    return func

@timer
def foo():
    time.sleep(0.1)

运行,出错,在__init__中找不到foo
ImportError: cannot import name foo

所以,关于装饰器是语法糖的等价解释并非在所有情况下都成立。例外之处在于:

  • 若先定义foo再设置foo=deco(foo),在执行deco时当前模块中已经包含了foo的定义;
  • 若直接将deco作为修饰器加在foo的定义上,则Python会在执行完deco之后才会将foo的(经过修饰的)定义加入到当前模块。

前面的例子中,可在timer函数中增加import __main__; print dir(__main__)验证上述结论。

你可能感兴趣的:(Python,python)