理解装饰器
-
原始简单程序
def say_hello(): print "hello!" def say_goodbye(): print "hello!" # bug here if __name__ == '__main__': say_hello() say_goodbye()
-
要求调用每个方法前都要记录进入函数的名称:
法一(low):def say_hello(): print "[DEBUG]: enter say_hello()" print "hello!" def say_goodbye(): print "[DEBUG]: enter say_goodbye()" print "hello!" if __name__ == '__main__': say_hello() say_goodbye()
法二:
def debug(): import inspect caller_name = inspect.stack()[1][3] print "[DEBUG]: enter {}()".format(caller_name) def say_hello(): debug() print "hello!" def say_goodbye(): debug() print "goodbye!" if __name__ == '__main__': say_hello() say_goodbye()
每个函数里都要调用一下debug()函数。
法三(装饰器):
def debug(func): def wrapper(): print "[DEBUG]: enter {}()".format(func.__name__) return func() return wrapper def say_hello(): print "hello!" say_hello = debug(say_hello) # 添加功能并保持原函数名不变
上面的debug函数其实已经是一个装饰器了,它对原函数做了包装并返回了另外一个函数,额外添加了一些功能。因为这样写实在不太优雅,在后面版本的Python中支持了@语法,下面代码等同于上面的写法。
def debug(func): def wrapper(): print "[DEBUG]: enter {}()".format(func.__name__) return func() return wrapper @debug def say_hello(): print "hello!"
-
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
概括的讲,装饰器的作用就是为已经存在的函数或对象添加额外的功能。
带参数的装饰器
-
上面程序中的装饰器是最简单的装饰器,但是有一个问题,如果被装饰的函数需要传入参数,那么这个装饰器就坏了。Python提供了可变参数*args和关键字参数**kwargs,有了这两个参数,装饰器就可以用于任意目标函数了。
def debug(func): def wrapper(*args, **kwargs): # 指定参数 print "[DEBUG]: enter {}()".format(func.__name__) print 'Prepare and say...', return func(*args, **kwargs) return wrapper # 返回 @debug def say(something): print "hello {}!".format(something) say('w')
结果: