关于Python的装饰器(1)

Python的装饰器的概念,一直有点微妙。之前在StackOverflow上看过一篇感觉说明的很清楚的介绍:

*A decorator must accept a function as an argument
 
参考地址:
 
Objects are data with methods attached, closures are functions with data attached.
 
英文水平有限,对于这句话我的理解一直是这样:
 1 def a(fn):
 2     print "function a"
 3     def tmpfun(*args):
 4         print "tmpfunc"
 5         fu(*args)
 6     return tmpfun
 7 
 8 @a
 9 def b(*args):
10     print "function b" + str(args)

 

此时,调用b(1, 2)等效于a(b(1, 2)),编译器解析代码时,会先执行b,然后执行a。
今天遇到有人问类似的问题,试着写了一下,发现等效方法运行出错。
经过实验,发现用装饰器修饰的b函数调用时,b(1, 2)等效于a(b)(1, 2)。
装饰器函数需要的参数应该是被修饰的函数对象,而不是被修饰函数对象的执行结果。
以下为验证代码:
 1 def addSpan(fn):
 2     print "addSpan executed"
 3     def n(*args):
 4         print "spam, spam, spam"
 5         return fn(*args)
 6     return n
 7 
 8 @addSpan
 9 def useful(a, b):
10     print a**2 + b**2
11 
12 def synonym(a, b):
13     print a**2 + b**2
14 
15 if __name__ == '__main__':
16     useful(3, 4)
17     addSpan(synonym)(3, 4)

执行结果为:

addSpan executed
spam, spam, spam
25
addSpan executed
spam, spam, spam
25
[Finished in 0.1s]

 

可以看出虽然形式上被修饰的函数会先被执行,但是实际执行时,仍然是以装饰器函数为入口开始执行的。

 

反思:

作为装饰器的函数必须接收参数,而且必须返回可执行的函数对象,否则将出错:

def a():
    print "function a"

@a
def b():
    print "function b"

b()

运行结果:

Traceback (most recent call last):
  File "/Users/.../decorator_test1.py", line 18, in <module>
    @a
TypeError: a() takes no arguments (1 given)
[Finished in 0.1s with exit code 1]

如果装饰器函数声明了参数,但是没有声明返回对象,或者声明的返回对象是不可被调用的对象,同样会出错:

def a(fn):
    print "function a"    // 没有声明返回对象

@a
def b():
    print "function b"

b()

执行结果:

Traceback (most recent call last):
  File "/Users/.../decorator_test1.py", line 27, in <module>
function a
    b()
TypeError: 'NoneType' object is not callable
[Finished in 0.1s with exit code 1]

可以看到后续动作将None作为返回对象继续执行,然后出错。

或者:

def a(fn):
    print "function a"
    return "asd"    // 声明返回对象为不可被调用的类型

@a
def b():
    print "function b"

b()

运行结果:

function a
Traceback (most recent call last):
  File "/Users/.../decorator_test1.py", line 28, in <module>
    b()
TypeError: 'str' object is not callable
[Finished in 0.1s with exit code 1]

 正常运行结果:

def a(fn):
    print "function a"
    return fn    // 返回参数获得的函数对象

@a
def b():
    print "function b"

b()

运行结果:

function a
function b
[Finished in 0.1s]

 

关于装饰器还有一些疑问,将在第二篇进行验证。

 

posted @ 2016-08-02 18:27 harelion 阅读(...) 评论(...) 编辑 收藏