Python 装饰器高级用法
外观
Python装饰器高级用法
介绍
Python装饰器是一种强大的语法结构,允许在不修改原函数代码的情况下动态扩展函数或类的功能。装饰器本质上是一个可调用对象(通常是函数或类),它接受一个函数作为输入并返回一个新的函数。装饰器在Python中被广泛用于日志记录、性能测试、权限验证等场景。
装饰器的高级用法包括:
- 带参数的装饰器
- 类装饰器
- 多个装饰器叠加使用
- 保持函数元信息
- 装饰器在类方法中的应用
基础装饰器回顾
在深入高级用法前,我们先回顾基础装饰器:
def simple_decorator(func):
def wrapper():
print("Before function execution")
func()
print("After function execution")
return wrapper
@simple_decorator
def greet():
print("Hello, World!")
greet()
输出:
Before function execution Hello, World! After function execution
带参数的装饰器
装饰器可以接受自定义参数,这需要额外的一层嵌套:
def repeat(num_times):
def decorator(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"Hello {name}")
say_hello("Alice")
输出:
Hello Alice Hello Alice Hello Alice
类装饰器
类也可以作为装饰器,只需实现__call__
方法:
class CountCalls:
def __init__(self, func):
self.func = func
self.num_calls = 0
def __call__(self, *args, **kwargs):
self.num_calls += 1
print(f"Call {self.num_calls} of {self.func.__name__}")
return self.func(*args, **kwargs)
@CountCalls
def example():
print("Inside example function")
example()
example()
输出:
Call 1 of example Inside example function Call 2 of example Inside example function
多个装饰器叠加
装饰器可以叠加使用,执行顺序是从下往上:
def decorator1(func):
def wrapper():
print("Decorator 1")
func()
return wrapper
def decorator2(func):
def wrapper():
print("Decorator 2")
func()
return wrapper
@decorator1
@decorator2
def my_func():
print("Original function")
my_func()
输出:
Decorator 1 Decorator 2 Original function
保持函数元信息
使用装饰器会导致原函数的元信息(如__name__
、__doc__
)丢失,可以使用functools.wraps
解决:
from functools import wraps
def preserve_metadata(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""Wrapper function docstring"""
return func(*args, **kwargs)
return wrapper
@preserve_metadata
def original_function():
"""Original function docstring"""
pass
print(original_function.__name__)
print(original_function.__doc__)
输出:
original_function Original function docstring
实际应用案例
性能计时器
import time
from functools import wraps
def timer(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
end = time.perf_counter()
print(f"{func.__name__} took {end - start:.4f} seconds")
return result
return wrapper
@timer
def slow_function(n):
sum = 0
for i in range(n):
sum += i
return sum
slow_function(1000000)
权限验证
def requires_admin(func):
@wraps(func)
def wrapper(user, *args, **kwargs):
if user.get('is_admin'):
return func(user, *args, **kwargs)
else:
raise PermissionError("Admin privileges required")
return wrapper
@requires_admin
def delete_database(user):
print(f"Database deleted by {user['name']}")
admin_user = {'name': 'Alice', 'is_admin': True}
regular_user = {'name': 'Bob', 'is_admin': False}
delete_database(admin_user) # 正常工作
delete_database(regular_user) # 抛出PermissionError
装饰器执行流程
数学表示
装饰器可以看作函数组合。给定函数和装饰器,装饰后的函数为:
对于带参数的装饰器:
总结
Python装饰器提供了强大的元编程能力,可以:
- 优雅地扩展函数功能
- 减少代码重复
- 分离关注点
- 实现各种横切关注点(如日志、缓存、验证)
掌握装饰器的高级用法将使你的Python代码更加灵活和可维护。