Python的装饰器的概念,一直有点微妙。之前在StackOverflow上看过一篇感觉说明的很清楚的介绍:
*A decorator must accept a function as an argument
参考地址:
http://stackoverflow.com/questions/13857/can-you-explain-closures-as-they-relate-to-python
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]
关于装饰器还有一些疑问,将在第二篇进行验证。
时间: 2024-10-07 22:51:01