引言
装饰器是 Python 中最优雅、最强大的特性之一。它允许你在不修改原函数代码的情况下,为函数添加额外功能。本文将带你从基础语法到实战应用,全面掌握装饰器。
一、装饰器基础语法
装饰器本质上是一个接受函数作为参数并返回新函数的高阶函数。
python
def my_decorator(func):
def wrapper():
print("函数执行前")
func()
print("函数执行后")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
# 输出:
# 函数执行前
# Hello!
# 函数执行后
二、4 个实用装饰器示例
1. 计时装饰器
python
import time
from functools import wraps
def timer(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} 执行时间:{end - start:.4f}秒")
return result
return wrapper
@timer
def slow_function():
time.sleep(2)
return "完成"
slow_function()
2. 重试装饰器
python
from functools import wraps
def retry(max_attempts=3):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except Exception as e:
if attempt == max_attempts - 1:
raise
print(f"重试 {attempt + 1}/{max_attempts}: {e}")
time.sleep(1)
return wrapper
return decorator
@retry(max_attempts=3)
def fetch_data():
# 模拟可能失败的网络请求
import random
if random.random() < 0.7:
raise ConnectionError("网络错误")
return "数据获取成功"
3. 缓存装饰器
less
from functools import wraps, lru_cache
def memoize(func):
cache = {}
@wraps(func)
def wrapper(*args):
if args in cache:
print(f"命中缓存:{args}")
return cache[args]
result = func(*args)
cache[args] = result
return result
return wrapper
@memoize
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10)) # 55
print(fibonacci(10)) # 直接从缓存返回
4. 权限验证装饰器
python
from functools import wraps
def require_login(func):
@wraps(func)
def wrapper(user, *args, **kwargs):
if not user.get('is_logged_in'):
raise PermissionError("用户未登录")
return func(user, *args, **kwargs)
return wrapper
@require_login
def view_profile(user):
return f"欢迎,{user['name']}!"
# 测试
user = {'name': '张三', 'is_logged_in': True}
print(view_profile(user)) # 欢迎,张三!
三、带参数的装饰器
python
from functools import wraps
def repeat(times):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(times=3)
def greet(name):
print(f"你好,{name}!")
greet("世界")
四、多装饰器执行顺序
python
def decorator_a(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("[A] 前置处理")
result = func(*args, **kwargs)
print("[A] 后置处理")
return result
return wrapper
def decorator_b(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("[B] 前置处理")
result = func(*args, **kwargs)
print("[B] 后置处理")
return result
return wrapper
@decorator_a
@decorator_b
def test():
print(">>> 函数执行 <<<")
test()
# 执行顺序:
# [A] 前置处理
# [B] 前置处理
# >>> 函数执行 <<<
# [B] 后置处理
# [A] 后置处理
五、最佳实践
- 使用 @wraps 保留原函数信息
python
from functools import wraps
def my_decorator(func):
@wraps(func) # 保留 __name__, __doc__ 等
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
- 装饰器类实现
ruby
class CountCalls:
def __init__(self, func):
wraps(func)(self)
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 hello():
print("Hello")
- 避免过度嵌套 - 超过 3 层装饰器时考虑重构
总结
装饰器是 Python 函数式编程的核心工具,掌握它能让你写出更优雅、可复用的代码。从简单的日志记录到复杂的权限控制,装饰器的应用场景无处不在。
关键点回顾:
- 装饰器 = 高阶函数(接收函数,返回函数)
- 使用 @wraps 保留原函数元数据
- 带参数装饰器需要三层嵌套
- 多个装饰器从下往上执行