1 入门
装饰器应该是Python里面最难理解的概念了,网络很多文章和教程都试图把装饰器讲的很明白,其实是讲明白了,但对于没有实际项目开发经验的人来说装饰器不容易掌握,且在日常业务开发中,尽快将业务开发完成上线才是首要任务,代码质量往往成为其次,偶尔闲来需要不断补充新的知识而不是细细品味已经上线的代码。
2 函数装饰器
既然是装饰,那么就是在函数真正执行之前(或者之后)进行一些装饰(包裹),装饰可以对函数的输入参数,也可以在函数运行之前进行一些操作,也可以在函数运行之后进行一些操作,装饰器只是一个语法糖(语法糖,就是这样写就是这样的结果,为什么是这样的结果?没有为什么)。
3 接近实际的例子
以日志输出为例,在日志系统设计中,往往会设计如下几个函数:
def debug(msg):
msg = "debug " + msg
print(msg)
def info(msg):
msg = "info " + msg
print(msg)
如果有很多日志级别如error,warn,trace等,那么msg = "debug" + msg
将会重复又重复,这个时候装饰器是可以派上用场,如之前所说,装饰器可以在函数执行之前对参数进行一些操作,这里主要就是对输入参数msg
进行操作,突然感觉装饰器也有点类似C++的模板,方便代码复用,当然这也是装饰器的重要意义。
4 使用装饰器
使用装饰器将提取一个wrapper函数(包裹函数),使用语法糖@do_log
完成装饰器的使用。
from functools import wraps
def do_log(func):
@wraps(func)
def wrapper(*args, **kw):
if func.__name__ == "debug":
msg = "debug {}".format(args[0])
elif func.__name__ == "info":
msg = "info {}".format(args[0])
else:
msg = "unknown {}".format(args[0])
return func(msg, **kw)
return wrapper
@do_log
def debug(msg):
print(msg)
@do_log
def info(msg):
print(msg)
if __name__ == "__main__":
debug("123")
info("abc")
当然这个例子还有许多地方值得完善,比如参数直接使用了args[0]
等,其实装饰器只是帮我们做了一件事情,即通过语法糖实现了 debug = do_log(debug)
,然后debug("123")
,执行的是wrapper("123")
。当然实际实现会比这里所说的略微复杂,但是大体如此。
5 总结
装饰器虽然是Python的重要语法糖,但是阅读开源代码来看使用没有那么普通,上述例子通过函数封装可以实现同样的工作,除非是已经习惯装饰器这种语法糖。