Python装饰器完全指南 - 来自Python Cheatsheet项目的深度解析
什么是Python装饰器
Python装饰器是一种强大的语法特性,它允许开发者在不修改原始函数或类代码的情况下,为其添加额外的功能。装饰器本质上是一个高阶函数,它接受一个函数作为参数并返回一个新的函数。这种设计模式遵循了"开放封闭原则" - 对扩展开放,对修改封闭。
基础装饰器实现
让我们从最简单的装饰器开始:
def simple_decorator(func):
def wrapper():
print("函数执行前操作")
func()
print("函数执行后操作")
return wrapper
@simple_decorator
def greet():
print("你好,世界!")
greet()
输出结果:
函数执行前操作
你好,世界!
函数执行后操作
这个例子展示了装饰器的基本结构:
- 定义一个装饰器函数
simple_decorator
,它接受一个函数func
作为参数 - 在装饰器内部定义一个包装函数
wrapper
- 在包装函数中添加额外的功能,并调用原始函数
- 返回包装函数
处理带参数的函数
实际开发中,我们经常需要装饰带参数的函数。这时可以使用*args
和**kwargs
来接收任意数量的位置参数和关键字参数:
def param_decorator(func):
def wrapper(*args, **kwargs):
print(f"准备执行函数 {func.__name__}")
result = func(*args, **kwargs)
print(f"函数 {func.__name__} 执行完毕")
return result
return wrapper
@param_decorator
def add(a, b):
return a + b
print(add(3, 5))
输出结果:
准备执行函数 add
函数 add 执行完毕
8
保留函数元信息
使用装饰器后,原始函数的元信息(如__name__
、__doc__
等)会被包装函数覆盖。为了解决这个问题,Python提供了functools.wraps
装饰器:
from functools import wraps
def preserve_meta(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""包装函数的文档字符串"""
return func(*args, **kwargs)
return wrapper
@preserve_meta
def example():
"""原始函数的文档字符串"""
pass
print(example.__name__) # 输出: example
print(example.__doc__) # 输出: 原始函数的文档字符串
带参数的装饰器
有时候我们需要装饰器本身也能接受参数。这种情况下,我们需要在装饰器外再包装一层函数:
from functools import wraps
def repeat(num_times):
def decorator(func):
@wraps(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 say_hello(name):
print(f"你好,{name}!")
say_hello("张三")
输出结果:
你好,张三!
你好,张三!
你好,张三!
类装饰器
装饰器不仅可以作用于函数,还可以作用于类。类装饰器的实现方式与函数装饰器类似:
def class_decorator(cls):
class WrappedClass(cls):
def __init__(self, *args, **kwargs):
print("类实例化前操作")
super().__init__(*args, **kwargs)
print("类实例化后操作")
return WrappedClass
@class_decorator
class MyClass:
def __init__(self, value):
self.value = value
print("原始初始化")
obj = MyClass(42)
输出结果:
类实例化前操作
原始初始化
类实例化后操作
类作为装饰器
Python还允许使用类来实现装饰器,这种方式特别适合需要维护状态的场景:
class CallCounter:
def __init__(self, func):
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
print(f"这是第 {self.count} 次调用")
return self.func(*args, **kwargs)
@CallCounter
def say_hi(name):
print(f"你好,{name}")
say_hi("李四")
say_hi("王五")
输出结果:
这是第 1 次调用
你好,李四
这是第 2 次调用
你好,王五
装饰器的实际应用场景
- 日志记录:自动记录函数调用信息
- 性能测试:测量函数执行时间
- 权限验证:检查用户权限
- 缓存:实现函数结果的缓存
- 重试机制:在失败时自动重试
- 输入验证:验证函数参数的有效性
装饰器的最佳实践
- 尽量使用
functools.wraps
保留原始函数元信息 - 保持装饰器的单一职责,每个装饰器只做一件事
- 避免过度使用装饰器,以免降低代码可读性
- 为装饰器编写清晰的文档说明
- 考虑装饰器的性能影响,特别是在高频调用的函数上
通过掌握Python装饰器,你可以编写出更加模块化、可重用和可维护的代码。装饰器是Python高级编程中的重要工具,合理使用可以大幅提升代码质量和开发效率。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考