在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)
;
它可以让某个函数在不做任何代码变动的情况下,增加额外功能;
其返回值也是一个函数对象;
它经常用于有切面需求的场景;
比如:插入日志、性能测试、事务处理、缓存、权限校验等场景;
一句话,装饰器的作用就是为已经存在的对象添加额外的功能;
例如:
def foo():
print('i`m foo')
现在,有个新需求,需要在函数中插入日志:
def foo():
print('i`m foo')
logging.info('foo`s log')
在其他函数,foo1(),foo2(),中也有这样的需求,
如果再在每个函数内写多一个logging就会造成大量代码的重复;
可以定义一个函数,专门处理日志,日志处理完后再执行业务代码;
def my_log(func):
logging.warn("This is %s`s log" % func.__name__)
func()
def foo1():
print('i`m foo1')
my_log(foo1)
虽然这样可以实现,但是每次都需要将一个函数作为参数传给my_log();
而且,这样还破坏了原有的代码逻辑结构(之前是运行foo1(),现在需要运行my_log(foo1));
那么,这时候就需要一个更好的解决方案----装饰器;
请看以下代码:
def my_log(func):
def wrapper(*args, **kwargs):\
logging.warn("%s is running" % unc.__name___)
return func(*args)
return warpper
def foo1():
print('i`m foo1')
foo1 = my_log(foo1)
foo1()
其中,my_log
就是装饰器,它将执行业务的函数func
包裹在函数里面;
看起来就像my_log
被装饰了;
上面的例子中,函数进入和退出时,被称为一个横切面(Aspect);
这种编程方式呗称为面向切面的编程
(Aspect-Oriented Programming);
装饰器中,@符号是它的语法糖;
在定义函数的时候使用,可以避免再一次赋值操作(为什么呢?foo1 = my_log(foo1)
);
def my_log(func):
def wrapper(*args, **kwargs):
logging.warn("%s is running" % unc.__name___)
return func(*args, **kwargs)
return wrappper
@my_log
def foo():
primt('i`m foo')
foo()
如上所示,这样我们就省去了foo = my_log(foo)
这一步;
如果有多个函数需要被修饰,直接使用@my_log
即可;
不需要重复修改函数,或增加新的封装。
程序可读性和可重复利用性大大提高;
装饰器的方便性,还要归功于python中,函数可以作为参数传递给其他函数;
可以被赋值给其它变量,可以作为返回值;
可以被定义在另一个函数里面;
未完待续。。。
本文为Larwas原创文章,转载无需和我联系,但请注明来自larwas博客 https://larwas.com
最新评论