装饰器是 Python 中一种强大的语法特性,它允许在不修改原函数代码的情况下动态地扩展函数的功能。装饰器本质上是一个高阶函数,它接受一个函数作为参数并返回一个新的函数。
基本装饰器
1. 简单装饰器示例
python
def my_decorator(func):
def wrapper():
print("函数执行前")
func()
print("函数执行后")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
输出:
函数执行前
Hello!
函数执行后
2. 装饰器的工作原理
@my_decorator
语法糖等价于say_hello = my_decorator(say_hello)
my_decorator
接收say_hello
函数作为参数- 返回
wrapper
函数,它"包裹"了原函数
带参数的装饰器
1. 函数带参数的装饰器
python
def decorator_with_args(func):
def wrapper(name):
print(f"准备调用 {func.__name__}")
func(name)
print(f"{func.__name__} 调用完成")
return wrapper
@decorator_with_args
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
2. 装饰器本身带参数
python
def repeat(num_times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Bob")
输出:
Hello, Bob!
Hello, Bob!
Hello, Bob!
类装饰器
装饰器不仅可以是函数,还可以是类:
python
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 example():
print("执行示例函数")
example()
example()
example()
输出:
函数已被调用 1 次
执行示例函数
函数已被调用 2 次
执行示例函数
函数已被调用 3 次
执行示例函数
多个装饰器叠加
可以同时应用多个装饰器:
python
def uppercase_decorator(func):
def wrapper():
result = func()
return result.upper()
return wrapper
def exclamation_decorator(func):
def wrapper():
result = func()
return result + "!"
return wrapper
@exclamation_decorator
@uppercase_decorator
def say_hi():
return "hi there"
print(say_hi()) # 输出: HI THERE!
注意:装饰器的应用顺序是从下往上,先应用 uppercase_decorator
,然后是 exclamation_decorator
。
内置装饰器
Python 本身提供了一些内置装饰器:
@staticmethod
- 定义静态方法@classmethod
- 定义类方法@property
- 将方法转换为属性
装饰器的常见用途
- 日志记录
- 性能测试(计算函数执行时间)
- 权限验证
- 缓存(备忘录模式)
- 输入验证
- 注册插件
- 重试机制
性能测试装饰器示例
python
import time
def timer(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
@timer
def slow_function():
time.sleep(2)
slow_function()
保留原函数的元信息
使用 functools.wraps
可以保留原函数的元信息:
python
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""这是包装函数的文档字符串"""
print("装饰器添加的功能")
return func(*args, **kwargs)
return wrapper
@my_decorator
def example():
"""这是原函数的文档字符串"""
print("原函数功能")
print(example.__name__) # 输出: example
print(example.__doc__) # 输出: 这是原函数的文档字符串
总结
装饰器是 Python 中非常强大的特性,它:
- 允许在不修改原函数代码的情况下扩展功能
- 遵循开放-封闭原则(对扩展开放,对修改封闭)
- 使代码更加模块化和可重用
- 常用于日志、性能测试、权限控制等场景
掌握装饰器可以让你写出更加优雅和高效的 Python 代码。