概述
顾名思义,所谓装饰器就是对原有的对象做一些装饰,也就是给已有的对象添加一些功能。
假如我现在想在函数运行时输出一些信息
小学水平
1 2 3 4 5 6 7 8 9
| def running(func): print '`%s` is running...' % func.__name__ return func @running def my_sum(): return "I cat't sum right now!" print my_sum()
|
输出
1 2
| `my_sum` is running... I cat't sum right now!
|
要使用装饰器,先得定义一个装饰器函数,然后在需要装饰的函数的前一行使用@符号加上装饰器名称。
在这里的效果等效于running(my_sum)(),不过看起来有点别扭。
注意:一旦通过@running装饰了函数,不管被装饰函数是否运行,python解释器都会执行一遍running函数。
中学水平
上一个装饰器用起来还行,但是有一个致命的问题,它不能装饰带参数的函数。所以我们在装饰器内部定义_wrapper函数,并返回它。这个函数接收所有位置参数*args,和关键字参数*kwargs,在_wrapper内部执行func(*args, **kwargs)。
1 2 3 4 5 6 7 8 9 10 11 12
| def running(func): def _wrapper(*args, **kwargs): print '`%s` is running...' % func.__name__ return func(*args, **kwargs) return _wrapper @running def my_sum(a, b=2): return a + b
print my_sum(1,2) print my_sum.__name__
|
输出
1 2 3
| `my_sum` is running... 3 _wrapper
|
这也是python中最普通的装饰器,假如需要在my_sum运行之后添加一些功能,则可以改成这样。
1 2 3 4 5 6 7 8 9 10
| import time
def running(func): def _wrapper(*args, **kwargs): start = time.time() print '`%s` is running...' % func.__name__ _result = func(*args, **kwargs) print 'run `%s` takes %s seconds' % (func.__name__, time.time()-start) return _result return _wrapper
|
大学水平
上一个装饰器也有一个问题,就是经过装饰的my_sum.__name__变成了_wrapper。
这个问题可以通过python内置的functools.wraps解决,这个装饰器对原函数的一些属性进行了复制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import time import functools
def running(func): @functools.wraps(func) def _wrapper(*args, **kwargs): start = time.time() print '`%s` is running...' % func.__name__ _result = func(*args, **kwargs) print 'run `%s` takes %s seconds' % (func.__name__, time.time()-start) return _result return _wrapper
@running def my_sum(a=1, b=2): time.sleep(1) return a + b
print my_sum(1,2) print my_sum.__name__
|
输出
1 2 3 4
| `my_sum` is running... run `my_sum` takes 1.0 seconds 3 my_sum
|