装饰器模式在python中的应用

装饰器模式:允许向一个现有的对象添加新的功能,同时又不改变其结构。在python中,装饰器可以是一个函数或者一个类。
 
在解释装饰器模式时,先理解下python中@符号的含义:
1、@符号是python中的一种修饰符,用来修饰函数,修饰符必须出现在函数定义的前一行,不允许和函数定义在同一行。
2、一个修饰符就是一个函数,它将修饰的函数作为参数,并返回修饰后的同名函数或者其他可以调用的类型。
 
书面解释比较抽象,来看一个例子:
import time
def get_current_time(func):
    print time.time()
    return func()
 
@get_current_time
def sum():
    print "sum 函数求和"
 
运行结果:
1531305351.73
sum 函数求和
其中@符号修饰了sum函数,相当于将sum函数作为参数传入了get_current_time函数,然后执行了get_current_time函数的主体流程。
 
python中装饰器模式应用分为:
1、函数装饰器,可以理解为装饰器为某个定义的函数。
2、带参数的装饰器,可以理解为装饰器函数可以包含参数传递。
3、类装饰器,可以理解为装饰器为一个定义的类,这种情况一般应用较少。
python内置装饰器有@staticmathod、@classmethod、@property,分别对应静态方法,类方法,类属性。
 
先看函数装饰器:
import logging
 
def get_logging(func):
    def wrapper(*args, **kwargs):
        logging.warn("this is debug log :%s"% func.__name__)
        return func(*args, **kwargs)
    return wrapper
 
@get_logging
def test_func():
    print "this is a test function"
 
if __name__ == '__main__':
    test_func()
 
输出结果为:
this is a test function
WARNING:root:this is debug log :test_func
函数get_logging就是装饰器,它将执行真正业务函数test_func包裹在函数中,看起来test_func被get_logging装饰了。简单解释下*args和**kwargs,*args作为函数参数时,是一种可变参数,可以传一个或者多个值,如果定义函数test(*args),那么调用test时,test(1,2,3,None,5),此时的args获取到的值为一个元组tuple,为(1,2,3,None,5);同理**args作为函数参数时,也是一种可变参数,区别是这里传递的值是以键值对呈现的,如果定义函数test(**args),那么调用test时,test(a = 1,b = 2,c = 3),此时的args获取到的值为一个字典dict,值为{'a':1,'b':2,'c':3}。
 
带参数的装饰器:
装饰器还有更大的宁活性,比如带参数的装饰器。装饰器的语法允许我们在调用时,提供其他参数,比如get_logging(flag),这样就为装饰器的执行提供了更大的灵活性。
比如将上面的例子稍微修改下:
import logging
 
def use_decorator(level):
    def get_logging(func):
        def wrapper(*args, **kwargs):
            if level == "warn":
                logging.warn("this is warn log :%s"% func.__name__)
            if level == "error":
                logging.error("this is error log :%s" % func.__name__)
            return func(*args, **kwargs)
        return wrapper
    return get_logging
 
@use_decorator(level = "error")
def test_func():
    print "this is a test function"
 
if __name__ == '__main__':
    test_func()
 
输出结果为:
ERROR:root:this is error log :test_func
this is a test function
给原来的get_logging外层加了一个use_decorator函数,实现函数参数的传递与判断。use_decorator是一个允许带参数的装饰器,实际是对原有装饰器的一个函数封装,并返回一个装饰器。
 
类装饰器:
相比如函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点,使用类装饰器还可以依靠内部的__call__方法,当使用@形式将装饰器附加到函数上时,就会调用此方法。
比如下面的例子:
class use_decorator(object):
    def __init__(self, func):
        self.func = func
 
    def __call__(self, *args, **kwargs):
        print "start execute decorator "
        self.func()
        print "end execute decorator "
 
@use_decorator
def test_func():
    print "this is a test function"
 
if __name__ == '__main__':
    test_func()
 
执行结果为:
start execute decorator 
this is a test function
end execute decorator 
相比于第一种函数装饰器,类装饰器是将原始方法传递到初始化__init__函数中,然后调用默认的__call__方法去完成装饰器的执行逻辑。
 
最后我们看看 多层装饰器的嵌套使用,例子如下:
def decorator_A(func):
    print "decorator A is call"
    return func
 
def decorator_B(func):
    print "decorator B is call"
    return func
 
def decorator_C(func):
    print "decorator C is call"
    return func
 
@decorator_A
@decorator_B
@decorator_C
def test_func():
    print "this is a test function"
 
if __name__ == '__main__':
    test_func()
 
执行结果为:
decorator C is call
decorator B is call
decorator A is call
this is a test function
从结果分析,先是执行了最里层装饰器函数decorator_C,然后将传入的方法test_func返回给了外层装饰器decorator_B,同样执行完decorator_B后将被装饰的方法作为参数传递给了装饰器decorator_A,最终完成被装饰器函数test_func的执行。整个过程相当于执行了:decorator_A(decorator_B(decorator_C(test_func)))。

猜你喜欢

转载自www.cnblogs.com/lihao7/p/9298681.html