匠心精神 - 良心品质腾讯认可的专业机构-IT人的高薪实战学院

咨询电话:4000806560

Python装饰器详解,提高代码复用性和扩展性

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中,装饰器是一个非常强大的工具,值得深入学习和使用。