Python 函数装饰器原理
装饰器是修改函数行为的语法工具,本质是函数替换机制。
装饰器本质
Python
@decorator
def func():
pass
# 等价于
def func():
pass
func = decorator(func)
无参数装饰器
Python
def my_decorator(func):
def wrapper():
print("调用前")
func()
print("调用后")
return wrapper
@my_decorator
def say_hello():
print("Hello")
say_hello()
# 输出:
# 调用前
# Hello
# 调用后
带参数的函数
Python
def my_decorator(func):
def wrapper(*args, **kwargs):
print(f"参数: {args}, {kwargs}")
result = func(*args, **kwargs)
print(f"结果: {result}")
return result
return wrapper
@my_decorator
def add(a, b):
return a + b
print(add(3, 5))
# 输出:
# 参数: (3, 5), {}
# 结果: 8
# 8
装饰器带参数
Python
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def greet(name):
print(f"Hello, {name}")
greet("Alice")
# 输出3次:
# Hello, Alice
# Hello, Alice
# Hello, Alice
装饰器调用流程
Python
@repeat(3)
def greet(name):
pass
解析步骤:
1. repeat(3) 返回 decorator 函数
2. decorator(greet) 返回 wrapper 函数
3. greet = wrapper(函数替换)
保持函数元信息
Python
from functools import wraps
def my_decorator(func):
@wraps(func) # 保持原函数的元信息
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@my_decorator
def example():
"示例函数"
pass
print(example.__name__) # example(而非 wrapper)
print(example.__doc__) # 示例函数
类作为装饰器
Python
class CountCalls:
def __init__(self, func):
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
print(f"调用次数: {self.count}")
return self.func(*args, **kwargs)
@CountCalls
def say_hello():
print("Hello")
say_hello() # 调用次数: 1
say_hello() # 调用次数: 2
多个装饰器叠加
Python
@decorator1
@decorator2
def func():
pass
# 等价于
func = decorator1(decorator2(func))
# 执行顺序: decorator2 -> decorator1(从内到外)
常用装饰器示例
text
import time
from functools import wraps
# 计时装饰器
def timer(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"{func.__name__} 耗时 {time.time() - start:.4f}s")
return result
return wrapper
# 日志装饰器
def logger(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"调用 {func.__name__}")
return func(*args, **kwargs)
return wrapper
@timer
@logger
def process():
time.sleep(1)
process()
# 输出:
# 调用 process
# process 耗时 1.00xxs
要点总结
- 装饰器本质是
func = decorator(func)的函数替换 - 无参数装饰器返回包装函数
- 带参数装饰器返回装饰器函数,再返回包装函数
- 使用
@wraps保持原函数元信息 - 类装饰器通过
__call__实现调用 - 多装饰器叠加从内到外执行
- 装饰器用于日志、计时、权限、缓存等场景
📝 发现内容有误?点击此处直接编辑