在Python编程的世界里,装饰器(Decorator)无疑是最优雅且强大的特性之一。它不仅能让你的代码更加简洁易读,还能大幅提升代码的复用性和可维护性。无论你是Python初学者还是经验丰富的开发者,掌握装饰器都将让你的编程技能更上一层楼。
目录
什么是装饰器?
装饰器是Python中一种特殊的语法糖,它允许我们在不修改原函数代码的情况下,为函数添加额外的功能。简单来说,装饰器就是一个接受函数作为参数并返回新函数的函数。
想象一下,你有一个房子(原函数),装饰器就像是为房子添加装修(新功能),而不需要拆掉重建。
# 最简单的装饰器示例
def my_decorator(func):
def wrapper():
print("装饰器开始工作")
func()
print("装饰器工作结束")
return wrapper
@my_decorator
def say_hello():
print("Hello, World!")
# 调用函数
say_hello()
输出:
装饰器开始工作
Hello, World!
装饰器工作结束
装饰器的工作原理
要深入理解装饰器,我们需要明白Python中的几个核心概念:
1. 函数是一等公民
在Python中,函数可以像变量一样被传递、赋值和返回:
def greet():
return "Hello!"
# 函数可以赋值给变量
my_func = greet
print(my_func()) # 输出: Hello!
# 函数可以作为参数传递
def call_function(func):
return func()
print(call_function(greet)) # 输出: Hello!
2. 闭包的概念
装饰器的核心机制依赖于闭包:
def outer_function(x):
def inner_function(y):
return x + y # inner_function可以访问outer_function的变量
return inner_function
add_10 = outer_function(10)
print(add_10(5)) # 输出: 15
3. 装饰器的等价写法
使用@语法糖:
@my_decorator
def my_function():
pass
等价于:
def my_function():
pass
my_function = my_decorator(my_function)
基础装饰器实战
让我们通过几个实用的例子来掌握装饰器的基本用法:
1. 执行时间统计装饰器
import time
import functools
def timing_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} 执行时间: {end_time - start_time:.4f}秒")
return result
return wrapper
@timing_decorator
def slow_function():
time.sleep(1)
return "任务完成"
result = slow_function()
print(result)
2. 日志记录装饰器
import logging
from datetime import datetime
# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
def log_calls(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
logging.info(f"调用函数 {func.__name__}")
logging.info(f"参数: args={args}, kwargs={kwargs}")
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_calls
def divide(a, b):
return a / b
# 测试
print(divide(10, 2)) # 正常执行
print(divide(10, 0)) # 会抛出异常
3. 重试机制装饰器
import random
import time
def retry(max_attempts=3, delay=1):
def decorator(func):
@functools.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:
print(f"函数 {func.__name__} 在 {max_attempts} 次尝试后仍然失败")
raise e
print(f"第 {attempt + 1} 次尝试失败,{delay}秒后重试...")
time.sleep(delay)
return wrapper
return decorator
@retry(max_attempts=3, delay=0.5)
def unreliable_network_call():
if random.random() < 0.7: # 70%的概率失败
raise ConnectionError("网络连接失败")
return "数据获取成功"
# 测试重试机制
try:
result = unreliable_network_call()
print(result)
except ConnectionError as e:
print(f"最终失败: {e}")
带参数的装饰器
带参数的装饰器需要三层嵌套函数:
def rate_limit(calls_per_second):
def decorator(func):
last_called = [0.0] # 使用列表来存储可变值
@functools.wraps(func)
def wrapper(*args, **kwargs):
elapsed = time.time() - last_called[0]
left_to_wait = 1.0 / calls_per_second - elapsed
if left_to_wait > 0:
time.sleep(left_to_wait)
ret = func(*args, **kwargs)
last_called[0] = time.time()
return ret
return wrapper
return decorator
@rate_limit(2) # 每秒最多调用2次
def api_call():
print(f"API调用时间: {datetime.now().strftime('%H:%M:%S.%f')[:-3]}")
# 测试限流效果
for i in range(5):
api_call()
类装饰器的魅力
1. 单例模式装饰器
def singleton(cls):
instances = {}
@functools.wraps(cls)
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class DatabaseConnection:
def __init__(self):
print("创建数据库连接")
self.connection_id = id(self)
def query(self, sql):
return f"执行查询: {sql}"
# 测试单例模式
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(f"db1 ID: {db1.connection_id}")
print(f"db2 ID: {db2.connection_id}")
print(f"是否为同一实例: {db1 is db2}")
2. 属性验证装饰器
def validate_types(**expected_types):
def decorator(cls):
original_setattr = cls.__setattr__
def new_setattr(self, name, value):
if name in expected_types:
expected_type = expected_types[name]
if not isinstance(value, expected_type):
raise TypeError(f"{name} 必须是 {expected_type.__name__} 类型")
original_setattr(self, name, value)
cls.__setattr__ = new_setattr
return cls
return decorator
@validate_types(name=str, age=int, salary=float)
class Employee:
def __init__(self, name, age, salary):
self.name = name
self.age = age
self.salary = salary
# 测试类型验证
emp = Employee("张三", 30, 5000.0)
print(f"员工: {emp.name}, 年龄: {emp.age}, 薪资: {emp.salary}")
try:
emp.age = "三十" # 这会抛出TypeError
except TypeError as e:
print(f"类型错误: {e}")
装饰器的高级应用
1. 缓存装饰器
def memoize(func):
cache = {}
@functools.wraps(func)
def wrapper(*args, **kwargs):
# 创建缓存键
key = str(args) + str(sorted(kwargs.items()))
if key in cache:
print(f"缓存命中: {func.__name__}{args}")
return cache[key]
print(f"计算中: {func.__name__}{args}")
result = func(*args, **kwargs)
cache[key] = result
return result
# 添加清除缓存的方法
wrapper.clear_cache = lambda: cache.clear()
wrapper.cache_info = lambda: f"缓存大小: {len(cache)}"
return wrapper
@memoize
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# 测试缓存效果
print(f"fibonacci(10) = {fibonacci(10)}")
print(fibonacci.cache_info())
2. 权限控制装饰器
from enum import Enum
class Permission(Enum):
READ = "read"
WRITE = "write"
ADMIN = "admin"
def require_permission(required_permission):
def decorator(func):
@functools.wraps(func)
def wrapper(user, *args, **kwargs):
if not hasattr(user, 'permissions'):
raise PermissionError("用户没有权限信息")
if required_permission not in user.permissions:
raise PermissionError(f"需要 {required_permission.value} 权限")
return func(user, *args, **kwargs)
return wrapper
return decorator
class User:
def __init__(self, name, permissions):
self.name = name
self.permissions = permissions
@require_permission(Permission.READ)
def read_data(user, data_id):
return f"用户 {user.name} 读取数据 {data_id}"
@require_permission(Permission.ADMIN)
def delete_data(user, data_id):
return f"用户 {user.name} 删除数据 {data_id}"
# 测试权限控制
admin_user = User("管理员", [Permission.READ, Permission.WRITE, Permission.ADMIN])
normal_user = User("普通用户", [Permission.READ])
print(read_data(admin_user, "data_001"))
print(read_data(normal_user, "data_002"))
try:
delete_data(normal_user, "data_003") # 这会抛出权限错误
except PermissionError as e:
print(f"权限错误: {e}")
装饰器最佳实践
1. 始终使用 functools.wraps
# ❌ 错误做法
def bad_decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
# ✅ 正确做法
def good_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
def test_function():
"""这是一个测试函数"""
pass
# 比较效果
bad_decorated = bad_decorator(test_function)
good_decorated = good_decorator(test_function)
print(f"原函数名: {test_function.__name__}")
print(f"错误装饰后: {bad_decorated.__name__}") # wrapper
print(f"正确装饰后: {good_decorated.__name__}") # test_function
2. 装饰器组合的顺序
def bold(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return f"<b>{result}</b>"
return wrapper
def italic(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return f"<i>{result}</i>"
return wrapper
@bold
@italic
def say_hello():
return "Hello, World!"
print(say_hello()) # 输出: <b><i>Hello, World!</i></b>
3. 可选参数的装饰器
def smart_decorator(func=None, *, prefix="[LOG]"):
def decorator(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
print(f"{prefix} 调用 {f.__name__}")
return f(*args, **kwargs)
return wrapper
if func is None:
# 带参数调用: @smart_decorator(prefix="[DEBUG]")
return decorator
else:
# 无参数调用: @smart_decorator
return decorator(func)
# 两种使用方式
@smart_decorator
def function1():
return "function1 执行"
@smart_decorator(prefix="[DEBUG]")
def function2():
return "function2 执行"
function1() # 输出: [LOG] 调用 function1
function2() # 输出: [DEBUG] 调用 function2
常见陷阱与解决方案
1. 装饰器中的循环变量问题
# ❌ 错误做法
def create_multipliers():
multipliers = []
for i in range(3):
def multiplier(x):
return x * i # 这里的i会是循环结束时的值
multipliers.append(multiplier)
return multipliers
# ✅ 正确做法
def create_multipliers_fixed():
multipliers = []
for i in range(3):
def multiplier(x, factor=i): # 使用默认参数捕获当前值
return x * factor
multipliers.append(multiplier)
return multipliers
# 测试
bad_multipliers = create_multipliers()
good_multipliers = create_multipliers_fixed()
print("错误版本:")
for i, mult in enumerate(bad_multipliers):
print(f"multiplier {i}: 5 * ? = {mult(5)}")
print("\n正确版本:")
for i, mult in enumerate(good_multipliers):
print(f"multiplier {i}: 5 * {i} = {mult(5)}")
2. 装饰器的性能考虑
# 对于频繁调用的函数,要注意装饰器的性能开销
def performance_test():
import time
def simple_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
def heavy_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# 模拟重量级操作
time.sleep(0.001)
return func(*args, **kwargs)
return wrapper
def simple_function():
return 42
@simple_decorator
def decorated_simple():
return 42
@heavy_decorator
def decorated_heavy():
return 42
# 性能测试
iterations = 1000
start = time.time()
for _ in range(iterations):
simple_function()
print(f"原函数: {time.time() - start:.4f}秒")
start = time.time()
for _ in range(iterations):
decorated_simple()
print(f"轻量装饰器: {time.time() - start:.4f}秒")
start = time.time()
for _ in range(iterations):
decorated_heavy()
print(f"重量装饰器: {time.time() - start:.4f}秒")
# performance_test() # 取消注释来运行性能测试
总结
Python装饰器是一个强大而优雅的特性,它能够:
- 提升代码复用性 - 将通用功能抽象为装饰器,避免重复代码
- 增强代码可读性 - 通过声明式的方式表达函数的额外行为
- 保持代码整洁 - 分离核心逻辑和辅助功能
- 支持动态行为 - 在运行时为函数添加或修改功能
掌握装饰器不仅能让你写出更优雅的Python代码,还能帮助你更好地理解Python的高级特性。在实际开发中,合理使用装饰器能够显著提升代码质量和开发效率。
记住,优秀的装饰器应该:
- 功能单一且明确
- 保留原函数的元信息
- 处理好参数传递
- 考虑性能影响
- 提供清晰的文档
现在就开始在你的项目中使用装饰器,让你的Python代码更加优雅和强大吧!

被折叠的 条评论
为什么被折叠?



