python之装饰器
装饰器的作用就是给已经存在的对象添加额外的功能
基本格式:
def decorator(func):
    def inner(*args, **kwargs):
        return func(*args, **kwargs)
    return inner
func就是要传入的函数
可以这样使用:
def fun():
    return 'hello'
decorator(fun)
也可以这样使用:
@decorator
def fun():
    return 'hello'
(注意:@在装饰器这里是作为Python语法里面的语法糖写法,用来做修饰。)
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值 也是一个函数对象。 它经常用于有以下场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计。
def decor_a(fun):
    def decor_b():
        print('I am decor_b')
        fun()
        print('I am fun')
    return decor_b
上段代码可以给fun函数执行前后添加两个打印功能。
需要注意的是装饰器给对象添加完功能之后,对象名就变成了装饰器本身的内嵌函数名,比如第一段代码的装饰器内嵌函数为inner那么func对象被decorator装饰之后返回的对象名就是inner,如何解决这种问题呢?
python的内置模块functools里面有个wraps方法可以做到
比如:
def decorator(func):
    @wraps(func)
    def inner(*args, **kwargs):
        return func(*args, **kwargs)
    return inner
在python的flask框架中的路由装饰器@app.route('/index')里面,毋庸置疑肯定是用到的,因为视图函数名不能相同,当然不能个个都是‘inner’。
带参装饰器
我们也看到装饰器wraps也是带参数的,那我们是不是也可以定义带参数的装饰器呢,我们可以使用一个函数来包裹装饰器,调入这个参数。
def logs(logfile='out.log'):
    def logging_decorator(fun):
        @wraps(fun)
        def wrapped_function(*args, **kwargs):
            log_string = fun.__name__ + " Debug"
            print(log_string)
            # 打开logfile,并写入内容
            with open(logfile, 'a') as opened_file:
                opened_file.write(log_string + '\n')
            return fun(*args, **kwargs)
        return wrapped_function
    return logging_decorator
@logs()
def decor_a():
    pass
如果想要继承功能,比如写一个装饰器,我们还想继续多添加一些功能,那么就不需要重复写之前已经有的功能,直接继承过来就行,这个时候可以写类装饰器。
class Logs(object):
    def __init__(self, logfile='out.log'):
        self.logfile = logfile
    def __call__(self, fun):
        @wraps(fun)
        def wrapped_function(*args, **kwargs):
            log_string = fun.__name__ + " was called"
            print(log_string)
            # 打开logfile并写入
            with open(self.logfile, 'a') as opened_file:
                # 现在将日志打到指定的文件
                opened_file.write(log_string + '\n')
            self.notify()
            # 发送一个通知
            return fun(*args, **kwargs)
        return wrapped_function
    def notify(self):
        pass
@Logs()
def decor_a():
    pass
这个实现有一个优势,在于比嵌套函数的方式更加整洁,而且包裹一个函数还是使用跟以前一样的语法
现在,我们给 Logs 创建子类,来添加 email 的功能,当然这个功能不在这里详细赘述。
class EmailLogs(Logs):
    ''' 一个logit的实现版本,可以在函数调用时发送email给管理员 '''
    def __init__(self, email='admin@myproject.com', *args, **kwargs):
        self.email = email
        super(EmailLogs, self).__init__(*args, **kwargs)
    def notify(self):
        # 发送一封email到self.email # 这里就不做实现了
        pass
这里我们继续继承并重写notify方法,完成发送邮件的功能。
此时@EmailLogs 将会和 @Logs 产生同样的效果,但是在打日志的基础上,还会多发送一封邮件给管理员。
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号