如何在 Python 中创建和使用装饰器
了解如何在 Python 中编写和应用装饰器。掌握包装函数、修改行为、处理参数以及使用包装保存元数据。
概述
装饰器是 Python 最优雅、最强大的语法功能之一,允许您修改函数或类的行为,而无需永久更改其代码。它们广泛用于横切关注点,例如记录执行时间、强制用户身份验证、缓存结果(记忆)和审核 API 端点。
在底层,装饰器是一个高阶函数,它接受另一个函数作为参数,定义一个注入一些自定义逻辑的嵌套包装函数,并返回该包装函数。 Python 提供了一种干净的速记语法,使用“@”符号将装饰器应用于函数,使它们在视觉上优雅。
在编写装饰器时,您通常希望装饰函数支持任意数量的位置参数和关键字参数。您可以通过设计嵌套包装函数来接受“*args”和“**kwargs”并将它们传递给目标函数来实现这一点。此外,您应该在包装函数上使用 functools.wraps 来保留原始函数的文档字符串和名称元数据。
代码和执行输出
此脚本演示了编写日志装饰器并包装函数来检查输入、输出和元数据。
decorators_tutorial.py
在编辑器中尝试from functools import wraps
# 1. Defining a decorator
def log_execution(func):
@wraps(func) # Preserves original function metadata
def wrapper(*args, **kwargs):
print(f"[Log] Calling function: {func.__name__} with args: {args}")
result = func(*args, **kwargs)
print(f"[Log] Finished {func.__name__}. Result: {result}")
return result
return wrapper
# 2. Applying the decorator using @ syntax
@log_execution
def add_numbers(a, b):
"""Adds two numbers and returns the sum."""
return a + b
# 3. Invoking the decorated function
sum_result = add_numbers(15, 25)
print("Sum Result:", sum_result)
# Verifying metadata preservation
print("Docstring preserved:", add_numbers.__doc__)端子输出
[Log] Calling function: add_numbers with args: (15, 25)
[Log] Finished add_numbers. Result: 40
Sum Result: 40
Docstring preserved: Adds two numbers and returns the sum.逐步实施
- 定义一个外部装饰器函数,它将目标函数作为参数。
- 在嵌套包装函数上导入并应用 @functools.wraps(func) 以保护原始元数据。
- 实现wrapper(*args, **kwargs) 来捕获输入变量、注入逻辑并调用目标函数。
- 从装饰器头块返回包装函数对象。
- 直接在目标函数签名上方使用 @decorator_name 应用装饰器。
常见问题解答
为什么装饰器内部需要@functools.wraps?
如果没有包装,装饰函数就会失去其原始身份(其 __name__ 和 __doc__ 属性被嵌套包装函数的属性替换),这使得调试和代码自省变得困难。
我可以将多个装饰器应用于单个函数吗?
是的!您可以通过堆叠放置多个 @ 行来链接装饰器。 Python 从下往上应用它们(最接近函数定义的首先执行)。
相关主题
推荐的 Python 资源
通过相关的交互式教程、备忘单和代码比较来扩展您的知识。