实用指南:Python装饰器深度解析:从基础到高级用法
目录
『宝藏代码胶囊开张啦!』—— 我的 CodeCapsule 来咯!✨
写代码不再头疼!我的新站点 CodeCapsule 主打一个 “白菜价”+“量身定制”!无论是卡脖子的毕设/课设/文献复现,需要灵光一现的算法改进,还是想给项目加个“外挂”,这里都有便宜又好用的代码方案等你发现!低成本,高适配,助你轻松通关!速来围观 CodeCapsule官网
Python装饰器深度解析:从基础到高级用法
1. 引言
在Python编程世界中,装饰器(Decorator)是一种强大而优雅的编程工具,它允许我们在不修改原始函数或类代码的情况下,动态地增强其功能。装饰器本质上是一个高阶函数,它接受一个函数作为参数,并返回一个新的函数。这种设计模式不仅体现了Python的函数式编程特性,也展现了Python语言的灵活性和表现力。
装饰器在Python生态系统中无处不在,从简单的日志记录、性能测试,到复杂的Web框架路由、权限验证,都能看到装饰器的身影。掌握装饰器不仅能让你的代码更加简洁优雅,还能显著提高代码的可重用性和可维护性。
本文将深入探讨Python装饰器的各个方面,从基础概念到高级应用,帮助你全面掌握这一重要的Python特性。
2. 装饰器基础概念
2.1 什么是装饰器
装饰器是Python的一种语法糖,它提供了一种简洁的方式來修改或增强函数和方法的行为。从本质上讲,装饰器就是一个接受函数作为参数并返回函数的高阶函数。
数学上,我们可以将装饰器看作是一个函数变换:
d
e
c
o
r
a
t
o
r
:
F
→
F
′
decorator: F \rightarrow F'
decorator:F→F′
其中
F
F
F是原始函数,
F
′
F'
F′是增强后的函数。
2.2 函数作为一等公民
理解装饰器的前提是理解Python中函数的"一等公民"地位。在Python中,函数可以:
- 被赋值给变量
- 作为参数传递给其他函数
- 作为其他函数的返回值
- 在运行时创建和修改
def greet(name):
return f"Hello, {name}!"
# 函数赋值给变量
my_function = greet
print(my_function("Alice")) # 输出: Hello, Alice!
# 函数作为参数
def call_twice(func, arg):
return func(arg) + " " + func(arg)
print(call_twice(greet, "Bob")) # 输出: Hello, Bob! Hello, Bob!
# 函数作为返回值
def create_greeter(greeting):
def greeter(name):
return f"{greeting}, {name}!"
return greeter
hello_greeter = create_greeter("Hello")
print(hello_greeter("Charlie")) # 输出: Hello, Charlie!
2.3 闭包(Closure)
闭包是装饰器实现的基础,它指的是内部函数可以访问并记住其外部函数作用域中的变量,即使外部函数已经执行完毕。
def outer_function(message):
# 外部函数的变量
outer_var = "Outer: "
def inner_function():
# 内部函数可以访问外部函数的变量
return outer_var + message
return inner_function
my_closure = outer_function("Hello, Closure!")
print(my_closure()) # 输出: Outer: Hello, Closure!
3. 装饰器的工作原理
3.1 装饰器的基本结构
让我们从一个最简单的装饰器开始,了解其基本工作流程:
def simple_decorator(func):
"""简单的装饰器示例"""
def wrapper():
print("函数执行前")
result = func()
print("函数执行后")
return result
return wrapper
@simple_decorator
def say_hello():
print("Hello!")
# 调用被装饰的函数
say_hello()
输出:
函数执行前
Hello!
函数执行后
3.2 装饰器的执行过程
装饰器的执行过程可以通过以下流程图理解:
graph TD
A[定义装饰器函数] --> B[定义目标函数]
B --> C[使用@语法应用装饰器]
C --> D[装饰器接收目标函数]
D --> E[装饰器返回包装函数]
E --> F[包装函数替换原函数]
F --> G[调用包装函数]
G --> H[执行额外逻辑]
H --> I[调用原函数]
I --> J[返回最终结果]
3.3 装饰器的等价形式
理解装饰器的语法糖本质很重要:
# 使用装饰器语法
@simple_decorator
def function_one():
print("Function One")
# 等价于
def function_two():
print("Function Two")
function_two = simple_decorator(function_two)
4. 常用内置装饰器
Python提供了一些内置装饰器,它们在日常编程中非常有用。
4.1 @staticmethod 和 @classmethod
class Calculator:
PI = 3.14159
def __init__(self, value=0):
self.value = value
@staticmethod
def add(a, b):
"""静态方法 - 与类相关但不需要访问实例或类"""
return a + b
@classmethod
def get_pi(cls):
"""类方法 - 第一个参数是类本身"""
return cls.PI
def instance_method(self):
"""实例方法 - 第一个参数是实例本身"""
return self.value * 2
# 使用示例
print(Calculator.add(5, 3)) # 输出: 8
print(Calculator.get_pi()) # 输出: 3.14159
calc = Calculator(10)
print(calc.instance_method()) # 输出: 20
4.2 @property
@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 diameter(self):
"""直径是只读属性"""
return self._radius * 2
@property
def area(self):
"""面积是只读属性"""
return 3.14159 * self._radius ** 2
# 使用示例
circle = Circle(5)
print(f"半径: {circle.radius}") # 输出: 半径: 5
print(f"直径: {circle.diameter}") # 输出: 直径: 10
print(f"面积: {circle.area:.2f}") # 输出: 面积: 78.54
circle.radius = 10
print(f"新半径: {circle.radius}") # 输出: 新半径: 10
try:
circle.radius = -5 # 触发 ValueError
except ValueError as e:
print(f"错误: {e}")
5. 函数装饰器的进阶用法
5.1 处理带参数的函数
为了使装饰器能够处理带参数的函数,我们需要在包装函数中使用*args和**kwargs:
def logger(func):
"""记录函数调用信息的装饰器"""
def wrapper(*args, **kwargs):
print(f"调用函数: {func.__name__}")
print(f"位置参数: {args}")
print(f"关键字参数: {kwargs}")
result = func(*args, **kwargs)
print(f"返回值: {result}")
return result
return wrapper
@logger
def add_numbers(a, b, c=0):
return a + b + c
@logger
def greet_person(name, greeting="Hello"):
return f"{greeting}, {name}!"
# 测试
print(add_numbers(10, 20, c=5))
print(greet_person("Alice", greeting="Hi"))
5.2 保留函数的元信息
当使用装饰器时,原始函数的元信息(如函数名、文档字符串等)会被包装函数覆盖。我们可以使用functools.wraps来保留这些信息:
import functools
def preserve_metadata(func):
"""保留函数元信息的装饰器"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"执行函数: {func.__name__}")
return func(*args, **kwargs)
return wrapper
@preserve_metadata
def calculate_sum(a, b):
"""
计算两个数的和
Args:
a: 第一个数
b: 第二个数
Returns:
两个数的和
"""
return a + b
# 测试元信息保留
print(f"函数名: {calculate_sum.__name__}") # 输出: calculate_sum
print(f"文档字符串: {calculate_sum.__doc__}") # 输出完整的文档字符串
print(f"模块: {calculate_sum.__module__}") # 输出模块信息
5.3 带参数的装饰器
有时候我们需要装饰器本身也能接受参数,这需要再嵌套一层函数:
import time
import functools
def repeat(num_times):
"""重复执行函数的装饰器"""
def decorator_repeat(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
results = []
for _ in range(num_times):
result = func(*args, **kwargs)
results.append(result)
return results
return wrapper
return decorator_repeat
def retry(max_attempts=3, delay=1, exceptions=(Exception,)):
"""重试装饰器,在失败时自动重试"""
def decorator_retry(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
attempts = 0
while attempts < max_attempts:
try:
return func(*args, **kwargs)
except exceptions as e:
attempts += 1
if attempts == max_attempts:
raise e
print(f"尝试 {attempts} 失败: {e}, {max_attempts - attempts} 次重试剩余")
time.sleep(delay)
return wrapper
return decorator_retry
# 使用示例
@repeat(num_times=3)
def greet(name):
return f"Hello, {name}!"
@retry(max_attempts=3, delay=2, exceptions=(ValueError,))
def risky_operation(value):
"""模拟可能失败的操作"""
if value < 0.5:
raise ValueError("值太小!")
return f"操作成功,值: {value}"
print(greet("World")) # 输出: ['Hello, World!', 'Hello, World!', 'Hello, World!']
# 测试重试装饰器
import random
for i in range(5):
try:
result = risky_operation(random.random())
print(result)
except ValueError as e:
print(f"最终失败: {e}")
6. 类装饰器
除了函数装饰器,Python还支持类装饰器。类装饰器可以装饰类或函数,提供更强大的功能。
6.1 装饰类的装饰器
def singleton(cls):
"""单例装饰器,确保类只有一个实例"""
instances = {}
@functools.wraps(cls)
def wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return wrapper
def add_methods(**methods):
"""动态为类添加方法的装饰器"""
def decorator(cls):
for method_name, method_func in methods.items():
setattr(cls, method_name, method_func)
return cls
return decorator
# 额外的类方法
def to_dict(self):
"""将对象转换为字典"""
return {attr: getattr(self, attr) for attr in dir(self)
if not attr.startswith('_') and not callable(getattr(self, attr))}
def from_dict(cls, data):
"""从字典创建对象"""
return cls(**data)
@singleton
@add_methods(to_dict=to_dict, from_dict=classmethod(from_dict))
class Configuration:
"""配置管理器"""
def __init__(self):
self.host = "localhost"
self.port = 8080
self.debug = True
# 测试
config1 = Configuration()
config2 = Configuration()
print(f"config1 is config2: {config1 is config2}") # 输出: True
config1.host = "127.0.0.1"
print(f"config2.host: {config2.host}") # 输出: 127.0.0.1
print(f"配置字典: {config1.to_dict()}")
6.2 作为类的装饰器
我们也可以创建作为类的装饰器,这需要实现__init__和__call__方法:
class Timer:
"""计时装饰器类"""
def __init__(self, func):
functools.wraps(func)(self)
self.func = func
self.total_time = 0
self.call_count = 0
def __call__(self, *args, **kwargs):
self.call_count += 1
start_time = time.perf_counter()
result = self.func(*args, **kwargs)
end_time = time.perf_counter()
execution_time = end_time - start_time
self.total_time += execution_time
print(f"函数 {self.func.__name__} 执行时间: {execution_time:.6f} 秒")
print(f"平均执行时间: {self.total_time / self.call_count:.6f} 秒")
return result
def stats(self):
"""返回统计信息"""
return {
'total_calls': self.call_count,
'total_time': self.total_time,
'average_time': self.total_time / self.call_count if self.call_count > 0 else 0
}
class CountCalls:
"""计数调用装饰器类"""
def __init__(self, func):
functools.wraps(func)(self)
self.func = func
self.num_calls = 0
def __call__(self, *args, **kwargs):
self.num_calls += 1
print(f"调用 {self.func.__name__} 第 {self.num_calls} 次")
return self.func(*args, **kwargs)
# 使用示例
@Timer
@CountCalls
def fibonacci(n):
"""计算斐波那契数列"""
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
# 测试
print(f"斐波那契(10): {fibonacci(10)}")
print(f"统计信息: {fibonacci.stats()}")
7. 装饰器的高级用法
7.1 多个装饰器的堆叠
装饰器可以堆叠使用,执行顺序是从下往上(从最靠近函数的装饰器开始):
def decorator_one(func):
"""第一个装饰器"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("装饰器一: 前")
result = func(*args, **kwargs)
print("装饰器一: 后")
return result
return wrapper
def decorator_two(func):
"""第二个装饰器"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("装饰器二: 前")
result = func(*args, **kwargs)
print("装饰器二: 后")
return result
return wrapper
@decorator_one
@decorator_two
def example_function():
print("原始函数执行")
print("执行堆叠装饰器的函数:")
example_function()
输出:
执行堆叠装饰器的函数:
装饰器一: 前
装饰器二: 前
原始函数执行
装饰器二: 后
装饰器一: 后
7.2 条件装饰器
我们可以创建根据条件决定是否应用装饰器的装饰器:
def conditional_decorator(condition, decorator):
"""条件装饰器工厂"""
def conditional_wrapper(func):
if condition:
return decorator(func)
return func
return conditional_wrapper
# 使用环境变量或其他条件决定是否启用装饰器
DEBUG = True
@conditional_decorator(DEBUG, Timer)
def expensive_operation(data):
"""模拟耗时操作"""
time.sleep(0.1)
return sum(data) * 2
# 测试
result = expensive_operation([1, 2, 3, 4, 5])
print(f"结果: {result}")
7.3 装饰器在Web框架中的应用
装饰器在Web框架中有着广泛的应用,下面模拟Flask框架的路由装饰器:
class FlaskApp:
"""模拟Flask应用"""
def __init__(self):
self.routes = {}
self.before_request_handlers = []
self.after_request_handlers = []
def route(self, path, methods=None):
"""路由装饰器"""
if methods is None:
methods = ['GET']
def decorator(func):
for method in methods:
route_key = (method.upper(), path)
self.routes[route_key] = func
return func
return decorator
def before_request(self, func):
"""请求前处理装饰器"""
self.before_request_handlers.append(func)
return func
def after_request(self, func):
"""请求后处理装饰器"""
self.after_request_handlers.append(func)
return func
def dispatch_request(self, method, path):
"""分发请求"""
# 执行请求前处理
for handler in self.before_request_handlers:
handler()
# 查找并执行路由处理函数
route_key = (method.upper(), path)
if route_key in self.routes:
result = self.routes[route_key]()
else:
result = "404 Not Found"
# 执行请求后处理
for handler in self.after_request_handlers:
result = handler(result) or result
return result
# 创建应用实例
app = FlaskApp()
@app.before_request
def before_request():
print("=== 请求开始 ===")
@app.after_request
def after_request(response):
print(f"=== 请求结束,响应: {response} ===")
return response
@app.route('/')
def home():
return "欢迎来到首页!"
@app.route('/about', methods=['GET'])
def about():
return "关于我们"
@app.route('/api/data', methods=['GET', 'POST'])
def api_data():
return '{"data": "API数据"}'
# 测试路由
print(app.dispatch_request('GET', '/'))
print(app.dispatch_request('GET', '/about'))
print(app.dispatch_request('POST', '/api/data'))
print(app.dispatch_request('GET', '/not-found'))
8. 装饰器的最佳实践
8.1 保持装饰器的可重用性
好的装饰器应该是可重用的,不依赖于特定的函数或上下文:
import functools
import time
from typing import Callable, Any
def benchmark(func: Callable) -> Callable:
"""
基准测试装饰器
Args:
func: 要测试的函数
Returns:
包装后的函数
"""
@functools.wraps(func)
def wrapper(*args, **kwargs) -> Any:
start_time = time.perf_counter()
result = func(*args, **kwargs)
end_time = time.perf_counter()
execution_time = end_time - start_time
print(f"函数 {func.__name__} 执行耗时: {execution_time:.6f} 秒")
return result
return wrapper
def validate_arguments(*validators: Callable) -> Callable:
"""
参数验证装饰器
Args:
*validators: 验证器函数列表
Returns:
包装后的函数
"""
def decorator(func: Callable) -> Callable:
@functools.wraps(func)
def wrapper(*args, **kwargs) -> Any:
# 验证位置参数
for i, (arg, validator) in enumerate(zip(args, validators)):
if i < len(validators) and not validator(arg):
raise ValueError(f"参数 {i} 验证失败: {arg}")
# 这里可以扩展验证关键字参数
return func(*args, **kwargs)
return wrapper
return decorator
# 验证器函数
def is_positive(x):
return x > 0
def is_even(x):
return x % 2 == 0
# 使用示例
@benchmark
@validate_arguments(is_positive, is_even)
def process_numbers(a, b):
"""处理数字的函数"""
time.sleep(0.01) # 模拟耗时操作
return a * b
# 测试
try:
result = process_numbers(4, 6)
print(f"结果: {result}")
result = process_numbers(-1, 6) # 会触发验证错误
except ValueError as e:
print(f"错误: {e}")
8.2 调试和测试装饰器
创建专门用于调试和测试的装饰器:
def debug_args(func: Callable) -> Callable:
"""调试参数装饰器"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"调试: 调用 {func.__name__}")
print(f" 位置参数: {args}")
print(f" 关键字参数: {kwargs}")
result = func(*args, **kwargs)
print(f" 返回值: {result}")
return result
return wrapper
def mock_during_test(mock_return_value=None):
"""测试期间模拟函数行为的装饰器"""
import os
def decorator(func):
if os.getenv('TESTING') == 'True':
# 在测试环境中返回模拟值
@functools.wraps(func)
def mock_wrapper(*args, **kwargs):
print(f"模拟函数: {func.__name__}")
return mock_return_value
return mock_wrapper
else:
# 在生产环境中使用真实函数
return func
return decorator
# 使用示例
@debug_args
def complex_calculation(x, y, coefficient=1):
return (x + y) * coefficient
@mock_during_test(mock_return_value="模拟结果")
def external_api_call():
"""模拟外部API调用"""
return "真实API响应"
# 测试
print("=== 调试装饰器测试 ===")
complex_calculation(5, 10, coefficient=2)
print("\n=== 模拟装饰器测试 ===")
# 设置测试环境
import os
os.environ['TESTING'] = 'True'
print(f"外部API调用结果: {external_api_call()}")
# 恢复生产环境
os.environ['TESTING'] = 'False'
9. 完整代码示例
下面是一个综合性的完整示例,展示了装饰器在实际项目中的应用:
#!/usr/bin/env python3
"""
Python装饰器综合示例
展示装饰器在实际项目中的多种应用场景
"""
import functools
import time
import logging
from typing import Any, Callable, Dict, List, Optional
from datetime import datetime
import json
# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
class PerformanceMonitor:
"""性能监控装饰器类"""
def __init__(self, func: Callable):
functools.wraps(func)(self)
self.func = func
self.call_count = 0
self.total_time = 0.0
self.history: List[Dict] = []
def __call__(self, *args, **kwargs) -> Any:
self.call_count += 1
start_time = time.perf_counter()
try:
result = self.func(*args, **kwargs)
success = True
except Exception as e:
result = None
success = False
raise e
finally:
end_time = time.perf_counter()
execution_time = end_time - start_time
self.total_time += execution_time
# 记录执行历史
self.history.append({
'timestamp': datetime.now().isoformat(),
'args': str(args),
'kwargs': str(kwargs),
'execution_time': execution_time,
'success': success
})
logger.info(f"函数 {self.func.__name__} 执行完成 - "
f"耗时: {execution_time:.6f}s, "
f"总调用: {self.call_count}, "
f"平均耗时: {self.total_time/self.call_count:.6f}s")
return result
def get_stats(self) -> Dict[str, Any]:
"""获取统计信息"""
avg_time = self.total_time / self.call_count if self.call_count > 0 else 0
success_count = sum(1 for record in self.history if record['success'])
success_rate = success_count / len(self.history) if self.history else 0
return {
'function_name': self.func.__name__,
'total_calls': self.call_count,
'total_time': self.total_time,
'average_time': avg_time,
'success_rate': success_rate,
'history_size': len(self.history)
}
def clear_history(self):
"""清空历史记录"""
self.history.clear()
def cache_results(max_size: int = 128, ttl: int = 3600):
"""
缓存结果装饰器
Args:
max_size: 最大缓存数量
ttl: 缓存存活时间(秒)
"""
def decorator(func: Callable) -> Callable:
cache: Dict = {}
cache_keys: List = []
@functools.wraps(func)
def wrapper(*args, **kwargs) -> Any:
# 生成缓存键
cache_key = json.dumps({
'func_name': func.__name__,
'args': args,
'kwargs': kwargs
}, sort_keys=True)
current_time = time.time()
# 检查缓存是否存在且未过期
if cache_key in cache:
cached_data = cache[cache_key]
if current_time - cached_data['timestamp'] < ttl:
logger.debug(f"缓存命中: {func.__name__}")
return cached_data['result']
else:
# 缓存过期,删除
del cache[cache_key]
cache_keys.remove(cache_key)
# 执行函数并缓存结果
result = func(*args, **kwargs)
# 检查缓存大小,如果超过限制则删除最旧的缓存
if len(cache_keys) >= max_size:
oldest_key = cache_keys.pop(0)
del cache[oldest_key]
# 添加新缓存
cache[cache_key] = {
'result': result,
'timestamp': current_time
}
cache_keys.append(cache_key)
logger.debug(f"缓存新增: {func.__name__}, 缓存大小: {len(cache_keys)}")
return result
def clear_cache():
"""清空缓存"""
nonlocal cache, cache_keys
cache.clear()
cache_keys.clear()
logger.info(f"已清空函数 {func.__name__} 的缓存")
# 添加清空缓存的方法
wrapper.clear_cache = clear_cache
return wrapper
return decorator
def rate_limit(max_calls: int, time_window: int):
"""
速率限制装饰器
Args:
max_calls: 时间窗口内最大调用次数
time_window: 时间窗口(秒)
"""
def decorator(func: Callable) -> Callable:
calls: List[float] = []
@functools.wraps(func)
def wrapper(*args, **kwargs) -> Any:
current_time = time.time()
# 移除过期的时间戳
calls[:] = [call_time for call_time in calls
if current_time - call_time < time_window]
# 检查是否超过限制
if len(calls) >= max_calls:
wait_time = time_window - (current_time - calls[0])
raise RuntimeError(f"速率限制 exceeded. 请等待 {wait_time:.2f} 秒")
# 添加当前调用时间
calls.append(current_time)
return func(*args, **kwargs)
return wrapper
return decorator
def circuit_breaker(failure_threshold: int = 5,
recovery_timeout: int = 60,
expected_exceptions: tuple = (Exception,)):
"""
断路器装饰器
Args:
failure_threshold: 失败阈值
recovery_timeout: 恢复超时时间
expected_exceptions: 预期的异常类型
"""
def decorator(func: Callable) -> Callable:
state = 'CLOSED' # CLOSED, OPEN, HALF_OPEN
failure_count = 0
last_failure_time = 0
@functools.wraps(func)
def wrapper(*args, **kwargs) -> Any:
nonlocal state, failure_count, last_failure_time
current_time = time.time()
# 检查断路器状态
if state == 'OPEN':
if current_time - last_failure_time < recovery_timeout:
raise RuntimeError("断路器开启,服务暂时不可用")
else:
state = 'HALF_OPEN'
try:
result = func(*args, **kwargs)
# 成功调用,重置状态
if state == 'HALF_OPEN':
state = 'CLOSED'
failure_count = 0
return result
except expected_exceptions as e:
failure_count += 1
last_failure_time = current_time
# 检查是否达到失败阈值
if failure_count >= failure_threshold:
state = 'OPEN'
logger.error(f"断路器开启,失败次数: {failure_count}")
raise e
def get_state():
"""获取断路器状态"""
return {
'state': state,
'failure_count': failure_count,
'last_failure_time': last_failure_time
}
def reset():
"""重置断路器"""
nonlocal state, failure_count, last_failure_time
state = 'CLOSED'
failure_count = 0
last_failure_time = 0
# 添加状态查询和重置方法
wrapper.get_state = get_state
wrapper.reset = reset
return wrapper
return decorator
# 综合使用示例
@PerformanceMonitor
@cache_results(max_size=50, ttl=300) # 缓存5分钟
@rate_limit(max_calls=10, time_window=60) # 每分钟最多10次调用
@circuit_breaker(failure_threshold=3, recovery_timeout=30)
def api_call(user_id: int, action: str) -> Dict[str, Any]:
"""
模拟API调用
Args:
user_id: 用户ID
action: 操作类型
Returns:
API响应
"""
# 模拟网络延迟
time.sleep(0.1)
# 模拟偶尔的失败
import random
if random.random() < 0.2: # 20%的失败率
raise ConnectionError("API调用失败")
return {
'user_id': user_id,
'action': action,
'result': 'success',
'timestamp': datetime.now().isoformat(),
'data': {'value': random.randint(1, 100)}
}
def demo_decorators():
"""演示装饰器的综合使用"""
print("=" * 60)
print("Python装饰器综合演示")
print("=" * 60)
# 测试API调用
successful_calls = 0
failed_calls = 0
for i in range(15):
try:
print(f"\n调用 {i+1}:")
result = api_call(user_id=123, action=f"test_{i}")
print(f" 成功: {result}")
successful_calls += 1
# 显示断路器状态
state = api_call.get_state()
print(f" 断路器状态: {state}")
except Exception as e:
print(f" 失败: {e}")
failed_calls += 1
# 显示断路器状态
state = api_call.get_state()
print(f" 断路器状态: {state}")
# 添加延迟,避免速率限制
time.sleep(0.5)
# 显示性能统计
stats = api_call.get_stats()
print(f"\n性能统计:")
for key, value in stats.items():
print(f" {key}: {value}")
print(f"\n总调用: {successful_calls + failed_calls}")
print(f"成功: {successful_calls}")
print(f"失败: {failed_calls}")
print(f"成功率: {successful_calls/(successful_calls+failed_calls)*100:.1f}%")
if __name__ == "__main__":
demo_decorators()
10. 总结
通过本文的深入探讨,我们全面了解了Python装饰器的各个方面:
10.1 核心要点回顾
- 装饰器本质:装饰器是高阶函数,接受函数作为参数并返回新函数
- 语法糖:
@decorator等价于func = decorator(func) - 闭包作用:内部函数可以访问外部函数的变量,这是装饰器的基础
- 元信息保留:使用
@functools.wraps保留原函数的元信息
10.2 装饰器类型总结
| 类型 | 特点 | 适用场景 |
|---|---|---|
| 函数装饰器 | 简单灵活 | 函数增强、日志、缓存 |
| 类装饰器 | 状态保持 | 单例、计数器、状态管理 |
| 带参数装饰器 | 配置灵活 | 条件装饰、参数化功能 |
| 内置装饰器 | Python原生 | 属性管理、静态方法、类方法 |
10.3 最佳实践建议
- 始终使用
@functools.wraps:保持函数的元信息 - 考虑装饰器的通用性:设计可重用的装饰器
- 注意执行顺序:多个装饰器从下往上执行
- 合理处理异常:装饰器不应该隐藏重要的异常信息
- 性能考虑:避免在装饰器中执行耗时操作
10.4 实际应用价值
装饰器在实际项目中有着广泛的应用:
- Web开发:路由、中间件、权限验证
- 性能优化:缓存、延迟加载、连接池
- 系统监控:性能分析、日志记录、异常追踪
- 测试调试:模拟、验证、测试隔离
掌握装饰器不仅能让你的代码更加优雅和强大,还能让你更好地理解Python的函数式编程特性和元编程能力。装饰器是Python高级编程的重要工具,值得每个Python开发者深入学习和掌握。
记住,好的装饰器应该像好的工具一样:专注、可重用、不引人注目。当你能够熟练运用装饰器时,你会发现它们能极大地提高代码的质量和开发效率。

浙公网安备 33010602011771号