什么是Python装饰器?
Python装饰器(Decorator)是一种强大的语法特性,它允许你在不修改原有函数代码的情况下,动态地改变函数的行为。装饰器本质上是一个高阶函数,它接收一个函数作为参数,并返回一个新的函数。
装饰器的核心概念
装饰器的工作原理基于Python的几个重要特性:
- 函数是一等公民:函数可以作为参数传递,也可以作为返回值
- 闭包:内部函数可以访问外部函数的变量
- 语法糖:
@decorator语法提供了简洁的装饰器应用方式
基础装饰器实现
1. 最简单的装饰器
def my_decorator(func):
def wrapper():
print("函数执行前")
func()
print("函数执行后")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
# 调用
say_hello()
输出:
函数执行前
Hello!
函数执行后
2. 带参数的函数装饰器
def decorator_with_args(func):
def wrapper(*args, **kwargs):
print(f"调用函数: {func.__name__}")
print(f"参数: {args}, {kwargs}")
result = func(*args, **kwargs)
print(f"返回值: {result}")
return result
return wrapper
@decorator_with_args
def add(a, b):
return a + b
# 调用
add(3, 5)
输出:
调用函数: add
参数: (3, 5), {}
返回值: 8
装饰器的高级用法
1. 带参数的装饰器
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")
输出:
Hello, Alice!
Hello, Alice!
Hello, Alice!
2. 类装饰器
class CountCalls:
def __init__(self, func):
self.func = func
self.calls = 0
def __call__(self, *args, **kwargs):
self.calls += 1
print(f"函数被调用了 {self.calls} 次")
return self.func(*args, **kwargs)
@CountCalls
def say_whee():
print("Whee!")
say_whee()
say_whee()
输出:
函数被调用了 1 次
Whee!
函数被调用了 2 次
Whee!
3. 保留原函数元信息
from functools import wraps
def preserve_info(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@preserve_info
def example():
"""这是一个示例函数"""
pass
print(example.__name__) # 输出: example
print(example.__doc__) # 输出: 这是一个示例函数
实际应用场景
1. 性能监控装饰器
import time
from functools import wraps
def timing_decorator(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
@timing_decorator
def slow_function():
time.sleep(1)
return "完成"
slow_function()
2. 权限验证装饰器
def require_admin(func):
@wraps(func)
def wrapper(user, *args, **kwargs):
if user.get('role') != 'admin':
raise PermissionError("需要管理员权限")
return func(user, *args, **kwargs)
return wrapper
@require_admin
def delete_user(user, target_user):
print(f"用户 {target_user} 已被删除")
# 测试
admin_user = {'name': 'Alice', 'role': 'admin'}
regular_user = {'name': 'Bob', 'role': 'user'}
delete_user(admin_user, "Charlie") # 成功
# delete_user(regular_user, "Charlie") # 抛出异常
3. 缓存装饰器
def memoize(func):
cache = {}
@wraps(func)
def wrapper(*args):
if args in cache:
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)) # 快速计算,避免重复计算
4. 日志记录装饰器
import logging
logging.basicConfig(level=logging.INFO)
def log_execution(func):
@wraps(func)
def wrapper(*args, **kwargs):
logging.info(f"开始执行 {func.__name__}")
try:
result = func(*args, **kwargs)
logging.info(f"成功执行 {func.__name__}")
return result
except Exception as e:
logging.error(f"执行 {func.__name__} 时出错: {e}")
raise
return wrapper
@log_execution
def risky_operation():
# 可能出错的操作
return 10 / 0
装饰器的组合使用
def make_bold(func):
@wraps(func)
def wrapper():
return f"<b>{func()}</b>"
return wrapper
def make_italic(func):
@wraps(func)
def wrapper():
return f"<i>{func()}</i>"
return wrapper
@make_bold
@make_italic
def greet():
return "Hello, World!"
print(greet()) # 输出: <b><i>Hello, World!</i></b>
内置装饰器
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
@property
def area(self):
return 3.14159 * self._radius ** 2
c = Circle(5)
print(c.radius) # 5
c.radius = 10
print(c.area) # 314.159
2. @classmethod 和 @staticmethod
class MyClass:
@classmethod
def from_string(cls, string):
return cls(string)
@staticmethod
def is_valid(string):
return len(string) > 0
obj = MyClass.from_string("test")
print(MyClass.is_valid("test")) # True
3. @functools.lru_cache
from functools import lru_cache
@lru_cache(maxsize=128)
def expensive_function(n):
# 模拟耗时计算
return n * n
# 第一次调用会计算
print(expensive_function(5))
# 第二次调用直接返回缓存结果
print(expensive_function(5))
装饰器的最佳实践
- 始终使用@wraps:保留原函数的元信息
- 保持装饰器简单:每个装饰器只做一件事
- 考虑性能:装饰器会增加函数调用开销
- 文档化:清楚地说明装饰器的作用
- 测试:确保装饰器不会破坏原有功能
总结
Python装饰器是一个强大而灵活的工具,它可以:
- 增强函数功能而不修改源代码
- 保持代码的DRY原则(Don’t Repeat Yourself)
- 提高代码的可读性和可维护性
- 实现关注点分离
通过合理使用装饰器,你可以编写出更加优雅、高效的Python代码。从简单的日志记录到复杂的权限控制,装饰器都能提供优雅的解决方案。
