本文共 4558 字,大约阅读时间需要 15 分钟。
装饰器(Decorator)是 Python 中一个强大的功能,能够在不修改函数代码的情况下,动态地扩展函数的行为。它们广泛应用于代码的简洁化、权限管理、日志记录等领域。本文将从基础到高级讲解装饰器的使用方法及其实际应用场景。
在开始学习装饰器之前,首先需要明确一个关键概念:函数是对象。这意味着函数可以被赋值给变量,或者在另一个函数中被定义和调用。例如:
def hi(name="yasoob"): return "hi " + name# 调用函数并将结果输出print(hi()) # 输出: 'hi yasoob'
函数也可以作为变量赋值:
greet = hiprint(greet()) # 输出: 'hi yasoob'
这表明函数不仅可以被调用,还可以被用作变量,具备对象的属性。
在函数内部,可以定义另一个函数,并通过返回该函数来实现功能的延迟。例如:
def hi(name="yasoob"): def greet(): return "now you are in the greet() function" def welcome(): return "now you are in the welcome() function" print(greet()) # 输出: now you are in the greet() function print(welcome()) # 输出: now you are in the welcome() function
如果在外部调用 greet(),则会抛出 NameError,这表明 greet() 函数仅在 hi() 函数内部可用。
为了更加灵活地使用函数,可以将其作为返回值。例如:
def hi(name="yasoob"): if name == "yasoob": return greet else: return welcome# 调用并执行a = hi()print(a()) # 输出: now you are in the greet() function
这里,hi() 根据 name 的值返回 greet() 或 welcome() 函数,并在调用 a() 时执行返回的函数。
通过上述示例,可以看出装饰器的核心原理是:在函数执行前或执行后,插入自定义的代码逻辑。例如:
def a_new_decorator(a_func): def wrapTheFunction(): print("I am doing some boring work before executing a_func()") a_func() print("I am doing some boring work after executing a_func()") return wrapTheFunction# 使用装饰器def a_function_requiring_decoration(): print("I am the function which needs some decoration to remove my foul smell")a_function_requiring_decoration() # 输出: I am the function which needs some decoration...a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)a_function_requiring_decoration() # 输出: I am doing some boring work before executing a_func() 在 Python 中,装饰符 @ 是一个简洁的语法糖,用于将装饰器应用到函数上。例如:
@a_new_decoratordef a_function_requiring_decoration(): """Hey you! Decorate me!""" print("I am the function which needs some decoration to remove my foul smell") 这与直接赋值的方式等价:
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
装饰器在实际应用中可以用于多种场景,例如权限管理、日志记录等。以下是一个简单的权限管理装饰器示例:
from functools import wrapsdef 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
装饰器可以接受参数来定制行为。例如,一个带有日志文件路径的日志装饰器:
from functools import wrapsdef logit(logfile="out.log"): def logging_decorator(func): @wraps(func) def wrapped_function(*args, **kwargs): log_string = func.__name__ + " was called" print(log_string) with open(logfile, 'a') as opened_file: opened_file.write(log_string + '\n') return func(*args, **kwargs) return wrapped_function return logging_decorator
除了函数装饰器,类也可以用作装饰器。例如,一个带有日志文件和通知功能的类装饰器:
class logit(object): _logfile = 'out.log' def __init__(self, func): self.func = func def __call__(self, *args): log_string = self.func.__name__ + " was called" print(log_string) with open(self._logfile, 'a') as opened_file: opened_file.write(log_string + '\n') self.notify() def notify(self): pass
通过继承和扩展,可以创建更灵活的装饰器。例如,一个带有电子邮件通知的日志装饰器:
class email_logit(logit): def __init__(self, email='admin@myproject.com', *args, **kwargs): self.email = email super(email_logit, self).__init__(*args, **kwargs)
装饰器的实际应用场景无处不在。例如,在 Flask Web 框架中,常常使用装饰器来管理路由、权限和日志。以下是一个简单的日志记录和权限管理装饰器的组合使用示例:
from functools import wrapsfrom flask import request, redirect, url_forimport logginglogging.basicConfig(filename='app.log', level=logging.INFO)def log_request(func): @wraps(func) def wrapped(*args, **kwargs): logging.info(f"访问路径: {request.path}") return func(*args, **kwargs) return wrappeddef requires_auth(f): @wraps(f) def decorated(*args, **kwargs): if not request.is_authenticated: return redirect(url_for('login')) return f(*args, **kwargs) return decorated@app.route('/')@log_request@requires_authdef home(): return "你好,欢迎访问我们的主页" 在实际使用装饰器时,可能会遇到以下问题:
functools.wraps 保留函数属性。functools.wraps:保留函数的原始属性(如名称、文档字符串等)。通过以上知识和实践,您可以开始在自己的项目中灵活运用装饰器,提升代码的可维护性和可读性。
转载地址:http://kdofk.baihongyu.com/