python decrorator

用了python好久, 惭愧的是一些高级的语法糖就没怎么用过。花了点时间好好研究一下python 装饰器。
所谓装饰, 就是想要对一些已经有的模块做一些修饰工作, 但又不让这个功能侵入到原有代码中去,常用的使用场景例如, 插入日志, 性能测试, 事务处理等等, 有了装饰器, 就可以提取大量函数中与本身功能无关的代码,从而重用代码。

1
2
3
4
5
6
7
8
9
10
11
import datetime

def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper

@log
def now():
print(datetime.datetime.today())

对上面代码的注解:

  1. 函数log中需要一个func的参数, 也就是用来回调的函数。
  2. 在now函数前有一个@log, 即之前我们定义的函数

当我们调用now函数时, now()返回了wrapper()函数, 所以now其实变成了wrapper的一个变量, 而后面的log执行其实变成了wrapper()

1
2
3
now()
call now():
2015-06-18 11:00:52.339373

这样, 装饰器没有影响到原来的函数,也没影响函数调用的模块。

而多个装饰器,

1
2
3
4
@decorator1
@decorator2
def now():
print(datetime.datetime.today())

其实等价于 now = decorator1(decorator2(now))
(其实就是说装饰器的调用顺序与其声明的顺序相反)

而如果装饰器自己带参数, 其实就是说装饰器这个函数需要返回一个真正的decorator
比如:(本例子引用自廖雪峰python3装饰器)

1
2
3
4
5
6
7
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator

若调用

1
2
3
@log
def now():
print(datetime.datetime.today())

实际上就是
now = decorator(text)(now)

而如果被装饰的那个函数带参数, 则装饰器的函数也需要加入对应参数

1
2
3
4
5
6
7
8
9
10
def log(func):
def wrapper(text2):
print('%s' % (func.__name__))
return func(text2)
return wrapper

@log
def now(text2):
print(datetime.datetime.today())
print(text2)

比如调用

1
now("haha")

输出如下:

1
2
3
now
2015-06-18 11:20:11.246544
haha

简单的总结到这里, 比较好的例子可以参看
Python修饰器的函数式编程