装饰器基础:功能与概念
装饰器是Python中一项强大的功能,允许我们在不修改原始函数代码的情况下,为函数或方法添加额外的功能。装饰器本质上是一个接受函数作为参数并返回一个新函数的可调用对象。这种编程模式遵循开放封闭原则,即对扩展开放,对修改封闭。理解装饰器的核心在于认识到函数在Python中是一等对象,可以作为参数传递、从函数返回,并分配给变量。
装饰器的基本语法与实现
Python装饰器使用@符号作为语法糖,将其放置在函数定义之前。最基本的装饰器形式是一个外层函数嵌套一个内层函数。外层函数接收被装饰函数作为参数,内层函数通常称为包装函数,它负责执行装饰逻辑并调用原始函数。
简单装饰器示例
以下是一个简单的装饰器示例,它记录函数的执行时间:
import timedef timer_decorator(func): def wrapper(args, kwargs): start_time = time.time() result = func(args, kwargs) end_time = time.time() print(f{func.__name__} executed in {end_time - start_time} seconds) return result return wrapper@timer_decoratordef example_function(): time.sleep(2) return Doneresult = example_function()带参数的装饰器
有时我们需要装饰器本身能够接受参数,这就需要再嵌套一层函数。最外层函数接收装饰器参数,中间层接收被装饰函数,最内层实现装饰逻辑。
参数化装饰器示例
下面是一个带参数的装饰器示例,它可以指定重复执行函数的次数:
def repeat(num_times): def decorator_repeat(func): def wrapper(args, kwargs): for _ in range(num_times): result = func(args, kwargs) return result return wrapper return decorator_repeat@repeat(num_times=3)def greet(name): print(fHello {name})greet(World)类装饰器
除了函数装饰器,Python还支持类装饰器。类装饰器通过实现__call__方法使类实例可调用,从而作为装饰器使用。类装饰器通常更适用于需要维护状态的装饰场景。
类装饰器实现
以下是一个类装饰器的示例,它跟踪函数被调用的次数:
class CountCalls: def __init__(self, func): self.func = func self.num_calls = 0 def __call__(self, args, kwargs): self.num_calls += 1 print(fCall {self.num_calls} of {self.func.__name__}) return self.func(args, kwargs)@CountCallsdef say_hello(): print(Hello!)say_hello()say_hello()内置装饰器:property、staticmethod和classmethod
Python提供了几个内置装饰器,它们为面向对象编程提供了重要的功能。@property装饰器允许将方法作为属性访问,@staticmethod定义不需要访问实例或类的静态方法,@classmethod定义操作类而非实例的类方法。
内置装饰器应用
下面是这些内置装饰器的使用示例:
class MyClass: def __init__(self, value): self._value = value @property def value(self): return self._value @value.setter def value(self, new_value): self._value = new_value @classmethod def from_string(cls, string): return cls(int(string)) @staticmethod def is_integer(num): return isinstance(num, int)
装饰器堆叠与执行顺序
多个装饰器可以堆叠在一个函数上,它们按照从下到上的顺序执行。了解装饰器的执行顺序对于正确使用复杂装饰器组合至关重要。
装饰器堆叠示例
以下示例展示了两个装饰器的堆叠使用:
def decorator1(func): def wrapper(): print(Decorator 1) func() return wrapperdef decorator2(func): def wrapper(): print(Decorator 2) func() return wrapper@decorator1@decorator2def say_hello(): print(Hello!)say_hello()# 输出:# Decorator 1# Decorator 2# Hello!
functools.wraps保护元数据
使用装饰器时,原始函数的元数据(如函数名、文档字符串等)会被包装函数覆盖。functools.wraps装饰器可以解决这个问题,它将原始函数的元数据复制到包装函数中。
使用functools.wraps
下面是在装饰器中使用functools.wraps的示例:
from functools import wrapsdef my_decorator(func): @wraps(func) def wrapper(args, kwargs): Wrapper function docstring print(Something is happening before the function is called.) return func(args, kwargs) return wrapper@my_decoratordef example(): Example function docstring print(Hello from example!)print(example.__name__) # 输出: exampleprint(example.__doc__) # 输出: Example function docstring
装饰器在实际项目中的应用
装饰器在实际开发中有广泛的应用场景,包括但不限于:权限验证、日志记录、性能测试、事务处理、缓存结果和输入验证等。合理使用装饰器可以大大提高代码的可读性、可维护性和可复用性。
缓存装饰器示例
以下是一个简单的缓存装饰器实现,它可以存储函数的结果以避免重复计算:
from functools import wrapsdef cache(func): cached_results = {} @wraps(func) def wrapper(args): if args in cached_results: return cached_results[args] result = func(args) cached_results[args] = result return result return wrapper@cachedef fibonacci(n): if n < 2: return n return fibonacci(n-1) + fibonacci(n-2)
396

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



