Python-decorator技术指南
Python-decorator技术指南
- 装饰器核心概念
1.1 什么是装饰器?
装饰器是Python中一种强大的语法特性,它允许您在不修改原函数代码的情况下,为函数或类动态地添加新功能。装饰器本质上是一个接受函数作为参数并返回函数的高阶函数。
装饰器的核心思想遵循软件开发中的"开放封闭原则":对扩展开放(可以添加新功能),对修改封闭(不修改原有代码)。
1.2 装饰器语法糖
装饰器使用@decorator_name语法糖,这是一种简洁的表示法。例如:
@my_decorator
def my_function():
pass
完全等价于:
def my_function():
pass
my_function = my_decorator(my_function)
2. 装饰器工作原理与关键组件
2.1 闭包机制
装饰器依赖于闭包机制。内部函数可以访问外部函数的变量,即使在外部函数执行完毕后也是如此。
def simple_decorator(func):
def wrapper(args, **kwargs):
print("在函数执行前做一些事")
result = func(args, **kwargs)
print("在函数执行后做一些事")
return result
return wrapper
@simple_decorator
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
输出:
在函数执行前做一些事
Hello, Alice!
在函数执行后做一些事
2.2 使用functools.wraps保留元信息
直接使用装饰器会导致被装饰函数的元信息(如__name__、doc)丢失。使用@functools.wraps可以保留这些信息。
from functools import wraps
def advanced_decorator(func):
@wraps(func)
def wrapper(args, **kwargs):
print(f"准备调用函数: {func.name}")
result = func(args, **kwargs)
print(f"函数 {func.name} 调用完毕")
return result
return wrapper
@advanced_decorator
def example():
"""这是一个示例函数。"""
print("函数内部逻辑")
print(example.name) # 输出:example (而不是 'wrapper')
print(example.doc) # 输出:这是一个示例函数。
2.3 处理任意参数
使用*args和**kwargs确保装饰器可以处理任何参数类型的函数。
def universal_decorator(func):
@wraps(func)
def wrapper(args, **kwargs):
print("参数处理中...")
return func(args, **kwargs)
return wrapper
3. Python内置装饰器详解
3.1 @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 area(self):
"""计算面积,这是一个只读属性。"""
return 3.14159 * self._radius ** 2
c = Circle(5)
print(c.radius) # 5
c.radius = 10 # 设置半径
print(c.area) # 314.159
3.2 @staticmethod和@classmethod装饰器
class Date:
def init(self, year, month, day):
self.year = year
self.month = month
self.day = day
@classmethod
def from_string(cls, date_string):
"""类方法作为工厂,从字符串创建对象。"""
year, month, day = map(int, date_string.split('-'))
return cls(year, month, day)
@staticmethod
def is_leap_year(year):
"""静态方法,判断是否为闰年。"""
return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
使用类方法
date = Date.from_string('2023-10-27')
print(date.year, date.month, date.day) # 2023 10 27
使用静态方法
print(Date.is_leap_year(2024)) # True
3.3 @functools.lru_cache装饰器
用于缓存函数调用结果,提升性能。
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(30)) # 快速计算结果
print(fibonacci.cache_info()) # 查看缓存信息
3.4 @dataclasses.dataclass装饰器
简化数据类的定义。
from dataclasses import dataclass
@dataclass
class Person:
name: str
age: int
city: str = "Unknown"
person = Person("Alice", 30)
print(person) # Person(name='Alice', age=30, city='Unknown')
4. 常见应用场景
4.1 计时器装饰器
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} 耗时 {end - start:.6f} 秒")
return result
return wrapper
@timer
def slow_function():
time.sleep(1)
slow_function() # 函数 slow_function 耗时 1.000123 秒
4.2 权限校验装饰器
def requires_login(func):
@wraps(func)
def wrapper(user, *args, **kwargs):
if not user.get('is_authenticated'):
raise PermissionError("用户未登录,无法执行此操作")
return func(user, *args, **kwargs)
return wrapper
@requires_login
def view_user_profile(user):
print(f"正在显示用户 {user['name']} 的资料")
4.3 缓存装饰器
from functools import wraps
def cache(func):
cached_data = {}
@wraps(func)
def wrapper(args):
if args in cached_data:
print(f"缓存命中: args={args}")
return cached_data[args]
print(f"计算并缓存: args={args}")
result = func(args)
cached_data[args] = result
return result
return wrapper
5. 进阶用法
5.1 带参数的装饰器
def repeat(num_times):
"""装饰器工厂,根据参数生成不同的装饰器。"""
def decorator(func):
@wraps(func)
def wrapper(args, **kwargs):
for i in range(num_times):
print(f"第 {i+1} 次执行")
result = func(args, **kwargs)
return result
return wrapper
return decorator
@repeat(num_times=3)
def say_hello():
print("Hello!")
say_hello()
5.2 类装饰器
class CountCalls:
def init(self, func):
self.func = func
self.call_count = 0
def __call__(self, *args, **kwargs):
self.call_count += 1
print(f"函数 {self.func.__name__} 被第 {self.call_count} 次调用")
return self.func(*args, **kwargs)
@CountCalls
def example_function():
print("函数执行中...")
6. 第三方库中的装饰器
6.1 Flask路由装饰器
from flask import Flask
app = Flask(name)
@app.route('/hello')
def hello():
return "Hello, Flask!"
6.2 Django权限装饰器
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
# 只有登录用户才能访问
pass
7. 最佳实践与注意事项
7.1 使用建议
清晰优先:避免过度使用或嵌套过深的装饰器,以免降低代码可读性。
保留元数据:务必使用@functools.wraps,这对调试和文档生成至关重要。
理解执行顺序:当多个装饰器堆叠时,它们的应用顺序是自下而上的。
7.2 常见陷阱
忘记使用@wraps:会导致函数元信息丢失
装饰器执行时机:装饰器在函数定义时执行,而不是调用时
异常处理:确保装饰器不会吞掉原函数的重要异常
8. 总结
Python装饰器是一种极具表现力的编程工具,它将横切关注点(如日志、安全、缓存)与核心业务逻辑分离,极大地增强了代码的可复用性和可维护性。掌握装饰器是迈向Python高级编程的重要一步,在众多主流框架(如Flask、Django)中都有广泛应用。

浙公网安备 33010602011771号