Python装饰器(Decorator)是一种强大的语法特性,允许在不修改原函数代码的情况下,动态地增强函数或方法的功能。以下是装饰器的核心概念和用法:
一、装饰器基础
1. 最简单的装饰器
装饰器本质上是一个高阶函数,它接受一个函数作为输入,返回一个新的函数(或可调用对象)。
示例1:最简单的装饰器
def my_decorator(func):
def wrapper():
print("函数执行前...")
func()
print("函数执行后...")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
输出:
函数执行前...
Hello!
函数执行后...
2. 处理带参数的函数
如果被装饰的函数有参数,需要在内部函数(如wrapper)中使用*args和**kwargs接收任意参数。
示例2:支持参数的装饰器
def decorator_with_args(func):
def wrapper(*args, **kwargs):
print("装饰器:准备执行函数")
result = func(*args, **kwargs)
print("装饰器:函数执行完毕")
return result
return wrapper
@decorator_with_args
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
输出:
装饰器:准备执行函数
Hello, Alice!
装饰器:函数执行完毕
3. 带参数的装饰器
若装饰器本身需要参数,需要再嵌套一层函数来接收参数。
示例3:装饰器接受参数
def repeat(n_times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(n_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(n_times=3)
def say_hi():
print("Hi!")
say_hi()
输出:
Hi!
Hi!
Hi!
4. 保留原函数元信息
装饰器会覆盖原函数的元信息(如__name__),使用functools.wraps解决此问题。
示例4:保留原函数元信息
from functools import wraps
def preserve_metadata(func):
@wraps(func) # 保留原函数的元信息
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@preserve_metadata
def example():
"""示例函数"""
pass
print(example.__name__) # 输出 "example"
print(example.__doc__) # 输出 "示例函数"
输出:
example
示例函数
5. 类作为装饰器
类也可以作为装饰器,需实现__call__方法。
示例5:类实现的装饰器
import time
class TimerDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
start = time.time()
result = self.func(*args, **kwargs)
end = time.time()
print(f"{self.func.__name__} 执行耗时: {end - start:.2f}秒")
return result
@TimerDecorator
def slow_function():
time.sleep(1)
slow_function()
输出:
slow_function 执行耗时: 1.00秒
6. 装饰器的执行顺序
多个装饰器按照__从下到上__的顺序执行(靠近函数定义的先执行)。
@decorator1
@decorator2
def my_func():
pass
# 等效于:my_func = decorator1(decorator2(my_func))
二、装饰器的作用
- 代码复用:为多个函数统一添加日志、计时、权限验证等功能。
- 分离关注点:将业务逻辑与辅助功能(如日志)分离。
- 动态行为:运行时修改函数行为。
三、 常见应用场景
- 日志记录:记录函数调用信息。
- 性能测试:统计函数执行时间。
- 权限校验:检查用户权限。
- 缓存:缓存函数结果(如functools.lru_cache)。
- 路由注册:Web框架(如Flask)中的路由定义。
下一篇: 2. 装饰方法
262

被折叠的 条评论
为什么被折叠?



