python装饰器介绍
Python 2.2中引入的 classmethod() 和 staticmethod() 内置函数,你可以这样调用classmethod():
class A:
def foo(self, y):
print y
foo = classmethod(foo)
也可以这样:
class A:
@classmethod
def foo(self, y):
print y
虽然classmethod是内置函数,但它和普通的函数没有两样,因此你也可以创建自己的函数转化逻辑,如:
def mydecorator(func):
print 'mydecorator was called.'
func.name = 'myfun'
return func
该修饰器将稍微修改了原函数的逻辑:首先打印一段文字“mydecorator was called.”,然后给原函数添加了一个name属性,属性值为"myfun",之后再将函数放回,使用方法和调用结果如下:
class A:
@mydecorator
def foo(self, y):
print y
if __name__ == '__main__':
a = A()
a.foo(1)
运行结果为:
mydecorator was called. 1
以上简介我们可以大致了解了python装饰器的作用。
装饰器的调用逻辑
如上一节的示例中我们发现,使用装饰器的时候是@mydecorator,或者是foo=mydecorator(foo),而不是@mydecorator(),或者foo=mydecorator(foo)()。显然,我们要的装饰器是个函数,而不是函数的结果。因为我们要将我们要修饰的函数foo(即老函数)传递给修饰函数mydecorator,并且修饰函数mydecorator也返回一个新函数(上一的新函数是在老函数的基础上添加了一个属性)。
带参数装饰器
上一节的介绍装饰器的调用过程,我们可以明白,@mydecorator是个函数,而且是个函数就可以,实际上是必须要实现__call__方法的对象就可以了。也就是说装饰器可以定义成实现了__call__方法的class也可以是其他的任何返回函数的“对象”,后者实现较复杂,但功能强大。
实现__call__方法的class示例:
class mydecorator:
def __init__(self, func):
self.func = func
def __call__(self):
print “mydecorator was called.”
return self.func
使用方法同前面的示例一样,因为我们可以像函数一样调用该类:mydecorator(),不同的是,该类是以被装饰的函数作为构造参数,而不是作为__call__的参数。更复杂的装饰器:
def mydecorator(arg):
print “arg is ”, arg
def newdec(func):
print ‘new decorator was called.’
def replacedec(self):
print ‘replace decorator was called.self.count=’,self.count
return func(self)
return replacedec
return newdec
使用示例:
class A2:
def __init__(self):
self.count = -1
@mydecorator('yes')
def method(self):
print self.count
if __name__ == '__main__':
a = A2()
a.method()
输出结果:
Args is yes new decorator was called. decorator was called. self.count=-1 -1
要注意的是replacedec函数,可以看出该函数有一个参数self,该参数就是method的self参数,即A2对象。可以进一步总结出,装饰器的调用过程,对装饰器嵌套函数的解释:首先将”yes”参数传递装饰器mydecorator,然后将被装饰的函数作为参数传递给newdec嵌套函数,然后将被装饰的函数的参数做为参数传递给下一层嵌套的函数replacedec。如图:
多个参数的示例:
def mydecorator(arg1, arg2):
print "level 1 : Arg1=%s, arg2=%s" % (arg1, arg2)
def newdec(func):
print 'level 2 : newdec was called. the arg is func=%s' % func
def replace(self, x, y):
print "level 3 : replace was called. self is %s, x=%s, y=%s" % (str(self), str(x), str(y))
return func(self, x, y)
return replace
return newdec
class A2:
def __init__(self):
pass
@mydecorator('Hello', 'word.')
def method(self, x, y):
print x, y
if __name__ == '__main__':
a = A2()
a.method(1, 2)
运行结果为:
level 1 : Arg1=Hello, arg2=word. level 2 : newdec was called. the arg is func=<function method at 0x04A06130> level 3 : replace was called. self is <__main__.A2 instance at 0x04A05850>, x=1, y=2 1 2