@修饰符作为python语法中的一个修饰符,在修饰函数上有很多不可替代的特性,常应用与staticmethod和classmethod的声明中。
1.经典的old style风的方法转换
def enhanced(meth):
def new(self, y):
print "I am enhanced"
return meth(self, y)
return new
class C:
def bar(self, x):
print "some method says:", x
bar = enhanced(bar)
通过enhanced我们把bar升级成了一个new函数。
2.然而现在我们仅仅只需要通过一个@修饰符就能完成这种转换:
class C:
@classmethod
def foo(cls, y):
print "classmethod", cls, y
@enhanced
def bar(self, x):
print "some method says:", x
这里的bar也像1那样“enhance“成了一个new函数。而上面的foo函数我们也可以理解成它被“升级“成了一个类函数。
3.那么它具体是怎么实现的呢?
@synchronized
@logging
def myfunc(arg1, arg2, ...):
# ...do something
# decorators are equivalent to ending with:
# myfunc = synchronized(logging(myfunc))
# Nested in that declaration order
这里我用了一个修饰链(事实上就是函数的递归调用),修饰符@的作用等价于
myfunc = synchronized(logging(myfunc)),也就是说我们把myfunc作为一个参数传递给了修饰符中的函数并根据它的返回值给myfunc赋值。
我们举一个例子:
def addspam(fn):
def new(*args):
print ("spam, spam, spam",*args)
return fn(*args)
return new
@addspam
def useful(a, b):
print (a**2 + b**2)
useful(3,4)
它的输出:
spam, spam, spam 3 4
25
这里我解释一下它的输出:
首先当执行到@addspam时就发生了我如上所说的
useful=addspam( useful(3,4) )
看到addspam函数的定义,如果你明白了我1中讲述的函数转换你就能很快明白
addspam函数内定义了一个新函数new完成转换
这个new函数很简单:
我们加入了一个简单的输出print (“spam, spam, spam”,*args),然后就把这个函数原样返回了return fn(*args)。(其中fn就是useful的函数调用,*args就是useful的参数。)
然后我们将这个new函数返回就完成了这个”修饰符函数”。
最后当我们实际调用useful(3,4)时,根据我们刚刚的返回值useful=addspam( useful(3,4) ),useful**其实是没用任何的变化的**,所以当执行useful的时候就输出25,
因为@修饰符在声明时已经完成了一次useful的转换,我们之后就不要再在意addspam的定义啦~
参考来自https://www.ibm.com/developerworks/linux/library/l-cpdecor/index.html