装饰器(Decorator)是Python中一种强大的语法特性,它允许你在不修改原函数代码的情况下,为函数添加额外的功能。装饰器本质上是一个高阶函数,它接受一个函数作为参数,并返回一个新的函数。
一、装饰器基础
1. 最简单的装饰器示例
def my_decorator(func):
def wrapper():
print("函数执行前")
func()
print("函数执行后")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
输出:
函数执行前
Hello!
函数执行后
2. 装饰器的工作原理
使用@decorator
语法糖等同于:
def say_hello():
print("Hello!")
say_hello = my_decorator(say_hello) # 手动装饰
say_hello()
二、带参数的函数装饰器
1. 装饰带参数的函数
def decorator(func):
def wrapper(*args, **kwargs):
print(f"准备调用 {func.__name__}")
result = func(*args, **kwargs)
print(f"{func.__name__} 调用完成")
return result
return wrapper
@decorator
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
2. 装饰器本身带参数
def repeat(num_times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(num_times=3)
def greet(name):
print(f"Hello, {name}!")
greet("Bob")
三、类装饰器
装饰器不仅可以是函数,还可以是类:
1. 类作为装饰器
class CountCalls:
def __init__(self, func):
self.func = func
self.num_calls = 0
def __call__(self, *args, **kwargs):
self.num_calls += 1
print(f"调用次数: {self.num_calls}")
return self.func(*args, **kwargs)
@CountCalls
def say_hello():
print("Hello!")
say_hello()
say_hello()
2. 带参数的类装饰器
class DecoratorWithArgs:
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
def __call__(self, func):
def wrapper(*args, **kwargs):
print(f"装饰器参数: {self.args}, {self.kwargs}")
return func(*args, **kwargs)
return wrapper
@DecoratorWithArgs(1, 2, debug=True)
def test_func(x, y):
return x + y
print(test_func(10, 20))
四、内置装饰器
Python提供了一些有用的内置装饰器:
1. @property
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value < 0:
raise ValueError("半径不能为负")
self._radius = value
c = Circle(5)
print(c.radius) # 5
c.radius = 10
print(c.radius) # 10
2. @classmethod
和 @staticmethod
class MyClass:
class_attr = "类属性"
def __init__(self, value):
self.value = value
@classmethod
def class_method(cls):
print(f"访问类属性: {cls.class_attr}")
@staticmethod
def static_method():
print("这是一个静态方法")
MyClass.class_method() # 访问类属性: 类属性
MyClass.static_method() # 这是一个静态方法
3. @functools.wraps
解决装饰器导致的元信息丢失问题:
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__) # 输出 '示例函数文档' 而不是 '包装函数文档'
五、装饰器的高级用法
1. 多个装饰器叠加
def decorator1(func):
def wrapper():
print("装饰器1 - 前")
func()
print("装饰器1 - 后")
return wrapper
def decorator2(func):
def wrapper():
print("装饰器2 - 前")
func()
print("装饰器2 - 后")
return wrapper
@decorator1
@decorator2
def hello():
print("Hello!")
hello()
输出:
装饰器1 - 前
装饰器2 - 前
Hello!
装饰器2 - 后
装饰器1 - 后
2. 装饰器缓存(Memoization)
from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(30)) # 快速计算
3. 权限检查装饰器
def requires_admin(func):
def wrapper(user, *args, **kwargs):
if not user.is_admin:
raise PermissionError("需要管理员权限")
return func(user, *args, **kwargs)
return wrapper
class User:
def __init__(self, name, is_admin=False):
self.name = name
self.is_admin = is_admin
@requires_admin
def delete_database(user):
print(f"{user.name} 正在删除数据库...")
admin = User("Alice", is_admin=True)
regular = User("Bob")
delete_database(admin) # 正常工作
delete_database(regular) # 抛出PermissionError
六、装饰器的实际应用场景
-
日志记录:自动记录函数调用和参数
-
性能测试:测量函数执行时间
-
权限验证:检查用户权限
-
缓存:存储函数结果避免重复计算
-
事务处理:数据库操作前开始事务,操作后提交或回滚
-
输入验证:检查函数参数有效性
-
重试机制:函数失败时自动重试
-
API路由:Web框架中的路由注册
七、总结
Python装饰器是一种强大的元编程工具,它能够:
-
在不修改原函数代码的情况下扩展功能
-
保持代码干净和可复用
-
实现横切关注点(如日志、权限等)的集中管理
-
通过组合装饰器创建复杂行为
理解装饰器是掌握Python高级编程的重要一步,它广泛应用于Web框架(如Flask、Django)、测试框架和各种库中。