有函数如下,如何在不破坏函数的情况下为函数增加输出日志功能?
def say_nihao(): print('nihao')
很简单,我们只需要对函数进行封装即可
def log() print('我是日志') say_nihao()
现在我们只需要调用log()函数即可,相信很多人都是这样写的,但是这样写有很大的弊端。
- 我们需要找到程序中所有调用say_nihao()的地方改成log()如果现在又有一个函数say_hello()也需要增加输出日志功能,我们岂不是要再来一遍?也就是说我们刚才的 *** 作是不能复用的
下面我们来介绍python中的装饰器。
对于第一个问题,我们这样进行修改:
def log() print('我是日志') return say_hello say_nihao=log()
要解决第二个问题,我们只要把函数当作参数传递进去就可以了
def log(func) print('我是日志') return func say_nihao=log(say_nihao)
这样我们就不需要修改程序,并且代码可以复用,而log()我们称作装饰器。
我们通常将装饰器中增加的功能使用wrapper()包装起来,此时我们执行say_nihao()就相当于执行wrapper()
def log(func) def wrapper(): print('我是日志') return func return wrapper say_nihao=log(say_nihao)
在面向切面编程(AOP)中,我们将log()称为切面。将切面和具体函数结合的地方,也就是say_nihao=log(say_nihao)称为切入点。
如果say_nihao()函数有参数 ,我们可以这样:
def log(func) def wrapper(*args, **kwargs): print('我是日志') return func(*args, **kwargs) return wrapper say_nihao=log(say_nihao)
*args和**kwargs作用不在说明。
在python中为say_nihao=log(say_nihao)提供了一种语法糖:@
def log(func) def wrapper(*args, **kwargs): print('我是日志') return func(*args, **kwargs) return wrapper @log def say_nihao(): print('nihao')
这里说一下参数的问题,如果@log没有参数,那么传递到装饰器log()函数里的是say_nihao对象,如果@log(a)有参数,那么那么传递到装饰器log()函数里的是@log(a)里面的参数a,而say_nihao对象将被传递到wrapper()函数里。
基于此,如果装饰器本身需要参数,那么可以这么些:
def log(value): def decorator(func): def wrapper(*args, **kwargs) print(value) return func(*args, **kwargs) return wrapper return decorator @log('我是日志') def say_nihao(): print('nihao')
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)