装饰器

from functools import wraps
def decorator_name(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        if not can_run:
            return "Function will not run"
        return f(*args, **kwargs)
    return decorated

@decorator_name
def func():
    return "Function is running"

can_run = True
print(func())

can_run = Flase
print(func())
注意:@wraps接受⼀个函数来进⾏装饰,并加⼊了复制函数名称、注释⽂档、参数列表 等等的功能。这可以让我们在装饰器⾥⾯访问在装饰之前的函数的属性。


使⽤场景

授权(Authorization)

装饰器能有助于检查某个⼈是否被授权去使⽤⼀个web应⽤的端点(endpoint)。它们被⼤量

使⽤于Flask和Django web框架中。这⾥是⼀个例⼦来使⽤基于装饰器的授权:

from functools improt wraps

def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            authenticate()
        return f(*args, **kwargs)
    return decorated

⽇志(Logging)

⽇志是装饰器运⽤的另⼀个亮点。这是个例⼦:

from functools import wraps

def logit(func):
    @wraps(func):
        def with_logging(*args, **kwargs):
            print(func.__name__ + " was called")
            return func(*args, **kwargs)
        return with_logging
@logit
def addition_func(x):
    """Do some math."""
    return x + x
return = addition_func(4)

在函数中嵌⼊装饰器

我们回到⽇志的例⼦,并创建⼀个包裹函数,能让我们指定⼀个⽤于输出的⽇志⽂件。

from functools import wraps
def logit(logfile='out.log'):
    def logging_decorator(func):
        @wraps(func)
        def wrapped_function(func):
            log_string = func.__name__ + " was called"
            print(log_string)
            # 打开logfile,并写入内容
            with open(logfile, 'a') as open_file:
                # 现在将日志打到指定的logfile
                opened_file.write(log_string + '\n')
        return wrapped_function
    return logging_decorator

@logit()
def myfuncl():
    pass
myfunc1() 
# Output: myfunc1 was called 
# 现在⼀个叫做 out.log 的⽂件出现了,⾥⾯的内容就是上⾯的字符串 @logit(logfile='func2.log') 
def myfunc2(): 
    pass 
myfunc2(): 
    pass 
myfunc2() 
# Output: myfunc2 was called 
# 现在⼀个叫做 func2.log 的⽂件出现了,⾥⾯的内容就是上⾯的字符串

装饰器类

现在我们有了能⽤于正式环境的logit装饰器,但当我们的应⽤的某些部分还⽐较脆弱

时,异常也许是需要更紧急关注的事情。⽐⽅说有时你只想打⽇志到⼀个⽂件。⽽有时你

想把引起你注意的问题发送到⼀个email,同时也保留⽇志,留个记录。这是⼀个使⽤继承

的场景,但⽬前为⽌我们只看到过⽤来构建装饰器的函数。

幸运的是,类也可以⽤来构建装饰器。那我们现在以⼀个类⽽不是⼀个函数的⽅式,来重

新构建logit

class logit(object): 
    def __init__(self, logfile='out.log'):
        self.logfile = logfile 
    def __call__(self, func): 
        log_string = func.__name__ + " was called" 
        print(log_string) 
        # 打开logfile并写⼊ 
        with open(self.logfile, 'a') as opened_file: 
        # 现在将⽇志打到指定的⽂件 
            opened_file.write(log_string + '\n') 
            # 现在,发送⼀个通知 
            self.notify() def notify(self): 
            # logit只打⽇志,不做别的 
            pass

这个实现有⼀个附加优势,在于⽐嵌套函数的⽅式更加整洁,⽽且包裹⼀个函数还是使⽤

跟以前⼀样的语法:

@logit() 
def myfunc1(): 
    pass

现在,我们给logit创建⼦类,来添加email的功能(虽然email这个话题不会在这⾥展开)。

class email_logit(logit): 
    ''' 
    ⼀个logit的实现版本,可以在函数调⽤时发送email给管理员 
    ''' 
    def __init__(self, email='admin@myproject.com', *args, **kwargs) 
        self.email = email 
        super(logit, self).__init__(*args, **kwargs) 
    def notify(self): 
        # 发送⼀封email到self.email Python进阶
        # 这⾥就不做实现了 
        pass

从现在起,@email_logit将会和@logit产⽣同样的效果,但是在打⽇志的基础上,还

会多发送⼀封邮件给管理员。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容