摘要:装饰器是一个函数,它允许您包装另一个函数(添加或修改其行为),而无需更改原始函数的代码。这使得它们非常适合增强功能、执行规则或添加日志记录或安全检查等功能。
装饰器是一个函数,它允许您包装另一个函数(添加或修改其行为),而无需更改原始函数的代码。这使得它们非常适合增强功能、执行规则或添加日志记录或安全检查等功能。
装饰器包含在 Python 的标准库中。不需要外部依赖项或pip安装。
首先为此项目创建专用目录和虚拟环境。打开终端并运行:
视窗:
mkdir decorators_examplecd decorators_examplepython -m venv venvvenv\Scripts\activateLinux:
mkdir decorators_examplecd decorators_examplepython3 -m venv venvsource venv/bin/activate此设置可确保您在隔离的环境中工作,从而使您的依赖项保持井井有条。
从本质上讲,装饰器是一个函数,它将另一个函数作为输入,用附加行为包装它,然后返回修改后的函数。这允许您向现有函数添加新功能,而无需更改其代码。
将装饰器想象成礼品包装纸:原始礼品(功能)保持不变,但外观(装饰行为)发生变化。
让我们创建一个可重用的装饰器,为任何函数添加日志记录。虽然此示例重点关注日志记录,但相同的原则也适用于其他用例,例如身份验证、缓存或性能监控。
创建一个名为decorators.py的文件:
# decorators.pydef logger(func): def wrapper(*args, **kwargs): print(f"Calling function: {func.__name__}") result = func(*args, **kwargs) print(f"Function {func.__name__} completed") return result return wrapper解释:
logger函数采用函数 ( func ) 作为输入。它定义了一个嵌套wrapper函数,该函数在调用原始函数之前和之后添加行为。wrapper函数执行原始函数并返回其结果,但在其周围包含额外的步骤(日志记录)。让我们在现实场景中使用这个装饰器。创建一个名为store_operations.py的新文件:
# store_operations.pyfrom decorators import logger@loggerdef process_order(order_id, customer_name): print(f"Processing order {order_id} for {customer_name}") return f"Order {order_id} processed"@loggerdef update_inventory(item_id, quantity): print(f"Updating inventory for item {item_id}: {quantity} units") return f"Inventory updated for item {item_id}"if __name__ == "__main__": process_order(123, "Alice") update_inventory("SKU456", 50)解释:
@logger语法将装饰器应用于process_order和update_inventory 。每次调用这些函数之一时, logger装饰器都会在原始函数运行之前和之后添加日志记录行为。运行store_operations.py文件:
python store_operations.py输出:
Calling function: process_orderProcessing order 123 for AliceFunction process_order completedCalling function: update_inventoryUpdating inventory for item SKU456: 50 unitsFunction update_inventory completed即使您没有在process_order或update_inventory中显式添加日志记录代码,装饰器也会为您处理它。这展示了装饰器如何减少重复并使您的功能专注于其核心任务。
您无需在多个函数中编写相同的日志记录逻辑,而是将其封装在单个装饰器中。这使您的代码更易于维护。
干净的代码装饰器将函数的核心逻辑与其附加行为(例如日志记录或验证)分开。这使您的功能变得简单且集中。
灵活性您可以将装饰器应用于任何函数。例如,如果您添加生成发票之类的新功能,则可以使用相同的@logger装饰器,而无需重写代码。
装饰器不仅限于日志记录。让我们创建一个装饰器来限制函数何时可以运行。修改decorators.py文件:
# decorators.pyfrom datetime import datetimedef time_restricted(start_hour, end_hour): def decorator(func): def wrapper(*args, **kwargs): current_hour = datetime.now.hour if start_hour该装饰器检查当前时间,并且只允许包装的函数在指定的窗口期间运行。
修改store_operations.py :
from decorators import logger, time_restricted@logger@time_restricted(9, 17) # Only allow this function to run between 9 AM and 5 PMdef process_order(order_id, customer_name): print(f"Processing order {order_id} for {customer_name}") return f"Order {order_id} processed"if __name__ == "__main__": process_order(123, "Alice")在允许的时间范围内和之外运行脚本以查看装饰器如何工作。
保持装饰器简单:装饰器应该做好一项工作。避免让其承担过多的责任。适当时使用内置装饰器:Python 为常见用例提供了@staticmethod 、 @classmethod和@functools.lru_cache等装饰器。仔细组合装饰器:堆叠装饰器时,它们的应用顺序很重要。彻底测试以确保预期的行为。服务于不同目的的装饰器的其他示例。每个示例都建立在我们所涵盖的概念之上。
装饰器检查用户是否具有执行函数的正确权限。它在 Web 应用程序或 API 开发等需要访问控制的场景中非常有用。
代码实现创建或更新decorators.py :
# decorators.pydef require_permission(required_permission): def decorator(func): def wrapper(user_permissions, *args, **kwargs): if required_permission in user_permissions: return func(*args, **kwargs) else: print(f"Access denied: missing permission '{required_permission}'") return wrapper return decorator使用示例更新或创建名为access_control.py的文件:
# access_control.pyfrom decorators import require_permission@require_permission("edit")def edit_post(post_id): print(f"Editing post {post_id}")@require_permission("delete")def delete_post(post_id): print(f"Deleting post {post_id}")if __name__ == "__main__": user_permissions = ["view", "edit"] # Simulated user permissions edit_post(user_permissions, 101) # Allowed delete_post(user_permissions, 101) # Denied运行代码:
python access_control.py输出:
Editing post 101Access denied: missing permission 'delete'如果函数失败,装饰器会自动重试函数,这在网络调用或其他容易出现间歇性错误的操作中特别有用。
代码实现# decorators.pyimport timedef retry(max_retries, delay): def decorator(func): def wrapper(*args, **kwargs): for attempt in range(max_retries): try: return func(*args, **kwargs) except Exception as e: print(f"Attempt {attempt + 1} failed: {e}") time.sleep(delay) print("All attempts failed.") return wrapper return decorator使用示例创建一个名为retry_example.py的文件:
# retry_example.pyfrom decorators import retryimport random@retry(max_retries=3, delay=2)def unstable_operation: print("Attempting operation...") if random.random运行代码:
python retry_example.py输出(示例输出可能有所不同)
Attempting operation...Attempt 1 failed: Operation failed.Attempting operation...Attempt 2 failed: Operation failed.Attempting operation...Operation succeeded!装饰器强制函数的最大运行时间。如果函数超出限制,则会引发超时错误。
代码实现# decorators.pyimport signalclass TimeoutError(Exception): passdef time_limit(seconds): def decorator(func): def handle_timeout(signum, frame): raise TimeoutError(f"Function '{func.__name__}' timed out after {seconds} seconds") def wrapper(*args, **kwargs): signal.signal(signal.SIGALRM, handle_timeout) signal.alarm(seconds) try: return func(*args, **kwargs) finally: signal.alarm(0) # Disable the alarm return wrapper return decorator使用示例创建一个名为time_limiter.py的文件:
# time_limiter.pyfrom decorators import time_limitimport time@time_limit(3) # Function must finish within 3 secondsdef long_running_task: print("Starting long task...") time.sleep(5) # Simulates a long task print("Task completed.")if __name__ == "__main__": try: long_running_task except TimeoutError as e: print(e)运行代码:
python time_limiter.py输出:
Starting long task...Function 'long_running_task' timed out after 3 seconds!
来源:自由坦荡的湖泊AI