Python装饰器详解,提高代码复用性和扩展性 在Python中,装饰器是一种非常强大的语言特性,它可以使用现有函数来修改或增强它们的行为。使用装饰器,可以将某个函数的功能扩展到其他函数中,从而实现代码复用性和扩展性。 1. 装饰器是什么? 装饰器本质上是一个函数,它接受一个函数作为参数并返回一个函数。它可以修改或增强函数的行为,而无需修改函数的原始代码。装饰器通常被用来实现一些横切关注点(cross-cutting concerns),例如日志记录、性能监控、事务管理等。 下面是一个简单的装饰器示例: ```python def log_wrapper(func): def wrapper(*args, **kwargs): print(f"Calling function {func.__name__}") return func(*args, **kwargs) return wrapper @log_wrapper def my_function(): print("Hello World!") my_function() ``` 在上面的示例中,log_wrapper是一个装饰器函数,它接受一个参数func,并返回一个函数wrapper。wrapper函数可以在调用原始函数之前或之后执行一些操作。在这个例子中,wrapper函数记录了原始函数的名称,并在调用my_function之前打印它。通过使用@log_wrapper语法,我们将my_function传递给log_wrapper函数,从而创建一个新函数,该函数在调用my_function之前打印日志。 2. 带参数的装饰器 装饰器不仅可以接受函数作为参数,还可以接受其他参数。这使得我们可以创建带有配置选项的装饰器。 例如,我们可以编写一个带有阈值参数的装饰器,该参数指定函数执行的最长时间。如果函数的执行时间超过了阈值,则装饰器将打印一条警告消息: ```python import time def time_limit(threshold): def decorator(func): def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) end_time = time.time() duration = end_time - start_time if duration > threshold: print(f"Warning: function {func.__name__} took too long ({duration} seconds)") return result return wrapper return decorator @time_limit(0.1) def my_slow_function(): time.sleep(0.2) print("Done") my_slow_function() ``` 在上面的示例中,我们定义了一个名为time_limit的装饰器函数,它接受一个阈值参数,并返回一个装饰器函数decorator。decorator函数接受一个func参数,并返回一个包裹函数wrapper,该函数在调用原始函数之前记录开始时间,在调用之后记录结束时间,并计算两者之差。如果持续时间超过了阈值,则打印一条警告消息。 我们使用@time_limit(0.1)语法将my_slow_function传递给time_limit装饰器,从而创建一个新函数,该函数在调用my_slow_function之前检查其执行时间是否超过0.1秒。 3. 多个装饰器 一个函数可以有多个装饰器。这意味着多个装饰器可以依次对同一个函数进行修饰。 例如,我们可以编写一个带有缓存和时间限制功能的函数: ```python import time def cache(func): cache_dict = {} def wrapper(*args): if args in cache_dict: print(f"Result cached for {func.__name__} {args}") return cache_dict[args] else: result = func(*args) cache_dict[args] = result return result return wrapper def time_limit(threshold): def decorator(func): def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) end_time = time.time() duration = end_time - start_time if duration > threshold: print(f"Warning: function {func.__name__} took too long ({duration} seconds)") return result return wrapper return decorator @cache @time_limit(0.1) def my_slow_function(arg): time.sleep(0.2) return arg my_slow_function(1) my_slow_function(1) ``` 在上面的示例中,我们定义了两个装饰器函数cache和time_limit,并使用@cache和@time_limit语法将它们应用到my_slow_function中。由于@cache装饰器先被调用,因此在调用my_slow_function时,它首先检查缓存中是否存在结果。如果结果已经缓存,它将立即返回结果,而无需再次执行函数。否则,它将执行函数并将结果缓存。 @time_limit装饰器在这之后被调用。它使用相同的方式对my_slow_function进行修饰,但它添加了一个时间限制,以便在函数执行超过0.1秒时打印一条警告消息。 4. 类装饰器 装饰器不仅可以是函数,还可以是类。类装饰器可以用来修改类的定义或行为。 例如,我们可以编写一个类装饰器,该装饰器将类中的所有函数都替换为打印日志的版本: ```python class LogWrapper: def __init__(self, cls): self.cls = cls def __call__(self, *args, **kwargs): for name, value in vars(self.cls).items(): if callable(value): setattr(self.cls, name, self.log_func(value)) return self.cls(*args, **kwargs) def log_func(self, func): def wrapper(*args, **kwargs): print(f"Calling function {func.__name__}") return func(*args, **kwargs) return wrapper @LogWrapper class MyClass: def foo(self): print("Hello World!") def bar(self): print("Goodbye World!") my_object = MyClass() my_object.foo() my_object.bar() ``` 在上面的示例中,我们定义了一个名为LogWrapper的类装饰器,它接受一个类作为参数,并将该类中的所有函数替换为打印日志版本。LogWrapper类的__call__方法遍历原始类中的所有属性,并检查是否可调用。如果是,则将其替换为一个新函数,该函数在调用原始函数之前打印日志。 我们使用@LogWrapper语法将MyClass传递给LogWrapper装饰器,从而创建一个新类,其中所有函数都被修改为包含日志记录的版本。当我们创建一个MyClass对象并调用其中的方法时,它们都将打印日志。 5. 结论 Python装饰器是一种非常有用的语言特性,它允许我们编写可重用的代码,提高代码复用性和扩展性。使用装饰器,我们可以轻松地在不修改原始代码的情况下修改或增强函数的行为。我们可以使用装饰器来实现日志记录、性能监控、事务管理等横切关注点,也可以使用装饰器创建带有配置选项的函数。在Python中,装饰器是一个非常强大的工具,值得深入学习和使用。