python装饰器的概念建立在python中,一切皆是对象的基础上。正是因为一切皆是对象,所以函数可以作为参数传入,可以添加函数的功能。
装饰器简单来说就是对函数进行修饰,多用于添加函数的功能。接受和处理函数对象。企业级应用中最常用到,比如引入日志,增加性能检测功能,事务处理能力等等。
下面一步步来理解装饰器
def foo():
print "I am foo"
def deco(func):
print "I am deco, before %s called" %func.__name__
func()
print "I am deco, after %s called" %func.__name__
return func
这里deco已经有点装饰器的意思了,因为它接受一个函数对象func作为参数,在运行func的前后打印信息。试想,如果把print换成一些日志,或者统计功能,则实现了对func调用时添加了功能的目的。
最后将这个函数对象又作为返回值传递出去
def deco(func):
print "I am deco, before %s called" %func.__name__
func()
print "I am deco, after %s called" %func.__name__
return func
def foo():
print "I am foo"
foo = deco(foo)
foo()
这里foo用deco装饰,或者说调用了自己。本质上是foo指向了deco函数对象,这样我们在调用foo时,感觉除了打印两行信息,好像没什么区别,达到了统一调用的目的。
上述就实现了一个基本的装饰器功能,而python2.4之后,开始使用@语法糖来表示装饰器
def deco(func):
print "I am deco, before %s called" %func.__name__
func()
print "I am deco, after %s called" %func.__name__
return func
@deco
def foo():
print "I am foo"
foo()
在函数定义的上面,写上@+装饰器的名称,表示用该装饰器装饰这个函数,类似3中的函数包装。
@语句本质上就是执行
foo = deco(foo)
def deco(func):
# 内嵌函数
def _wrapped():
print "I am deco, before %s called" %func.__name__
func()
print "I am deco, after %s called" %func.__name__
return _wrapped
@deco
def foo():
print "I am foo"
foo()
将4中deco函数的动作封装到一个内嵌函数中,内嵌包装函数的形参和返回值与原函数相同,装饰器函数则返回内嵌包装函数对象。
因为4中在@装饰过程中执行了print,而这个过程是在函数定义过程中,也就是定义过程中就要执行print,这在很大程度上是不符合编程目的的。所以我们可以把这一动作用内嵌函数包装起来,这样print就只会在函数调用过程中执行。也能确保每次新函数都能被调用
def deco(func):
# 内嵌函数
def _wrapped(a, b):
print "I am deco, before %s called" %func.__name__
func(a, b)
print "I am deco, after %s called" %func.__name__
return _wrapped
@deco
def foo(a,b):
print "I am foo: %d" %(a+b)
foo()
因为被装饰的函数带参数,所以我们必须想办法把参数传递给它,所以就规定:内嵌函数的形参和返回值必须和被装饰函数相同,而装饰函数返回内嵌函数对象
这样我们在调用foo(a,b)的是,等价与调用_wrapped(a, b)
def deco(func):
# 内嵌函数
def _wrapped(*args, **kw):
print "I am deco, before %s called" %func.__name__
func(*args, **kw)
print "I am deco, after %s called" %func.__name__
return _wrapped
@deco
def foo1(a,b):
print "I am foo: %d" %(a+b)
@deco
def foo2(a,b,c):
print "I am foo: %d" %(a+b+c)
foo1()
foo2()
参数用(*args, **kw),自动适应变参和命名参数,可以让装饰器更加灵活,能够装饰更多的函数
def deco(args):
def _realDeco(func):
# 内嵌函数
def _wrapped(*args, **kw):
print "deco args: %s" %args
print "I am deco, before %s called" %func.__name__
func(*args, **kw)
print "I am deco, after %s called" %func.__name__
return _wrapped
return _realDeco
@deco("hello")
def foo1(a,b):
print "I am foo: %d" %(a+b)
@deco("world")
def foo2(a,b,c):
print "I am foo: %d" %(a+b+c)
foo1()
foo2()
要想让装饰器传入参数,则必须在外层再加一层包装。
以上就是装饰器的基本用法,更多用法可以参考官方文档。