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

咨询电话:4000806560

一篇文章学会Python中的装饰器

一篇文章学会Python中的装饰器

装饰器是Python中一种非常重要的函数式编程工具。它们允许开发人员将函数作为参数传递给另一个函数,并在执行函数之前或之后对其进行修改。在本文中,我们将深入研究Python中的装饰器,并了解如何使用它们进行函数修饰。

1.装饰器的定义

装饰器实际上是一个函数或类,它接受另一个函数作为参数并返回另一个函数。使用装饰器,您可以在不修改函数源代码的情况下修改函数的行为。这使得您可以轻松地添加新的功能,例如日志记录或性能评估。

下面是一个简单的装饰器示例,它通过在函数执行之前和之后打印消息来记录函数调用:

```
def log_calls(func):
    def wrapper(*args, **kwargs):
        print("Calling {} with arguments {} and {}".format(func.__name__, args, kwargs))
        result = func(*args, **kwargs)
        print("Returning {} from {}".format(result, func.__name__))
        return result
    return wrapper

@log_calls
def add(x, y):
    return x + y

result = add(2, 3)
print(result)
```

在上面的示例中,我们定义了一个名为“log_calls”的装饰器,它接受一个函数“func”作为参数并返回另一个函数“wrapper”。“wrapper”函数在函数“func”执行之前和之后打印消息,并最终返回函数“func”的结果。我们然后使用装饰器将“add”函数修饰为“log_calls”函数的输出。

当我们运行以上代码,输出如下:

```
Calling add with arguments (2, 3) and {}
Returning 5 from add
5
```

2.装饰器的语法

上面的示例中,我们使用了Python的语法糖来应用装饰器。实际上,您也可以使用以下语法将装饰器应用于函数:

```
def add(x, y):
    return x + y

add = log_calls(add)
```

这将把函数“add”传递给装饰器“log_calls”,并将返回值赋值给同名函数变量“add”。使用这种语法,您可以在没有语法糖的情况下使用装饰器。

3.多个装饰器

您可以在一个函数上应用多个装饰器。在这种情况下,装饰器将按照内部到外部的顺序应用于函数。例如,以下代码将应用两个装饰器:log_calls和memoize(用于缓存函数的结果):

```
def log_calls(func):
    def wrapper(*args, **kwargs):
        print("Calling {} with arguments {} and {}".format(func.__name__, args, kwargs))
        result = func(*args, **kwargs)
        print("Returning {} from {}".format(result, func.__name__))
        return result
    return wrapper

def memoize(func):
    cache = {}
    def wrapper(*args):
        if args in cache:
            return cache[args]
        result = func(*args)
        cache[args] = result
        return result
    return wrapper

@log_calls
@memoize
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

result = fibonacci(10)
print(result)
```

在上面的代码中,我们定义了两个装饰器:log_calls和memoize。我们然后将它们应用于函数“fibonacci”,并使用“@”符号按照从内到外的顺序来进行装饰。由于“memoize”装饰器首先被应用,因此它将缓存函数的结果,而“log_calls”装饰器将记录函数的调用。

当我们运行以上代码,输出如下:

```
Calling wrapper with arguments (10,) and {}
Calling wrapper with arguments (9,) and {}
Calling wrapper with arguments (8,) and {}
Calling wrapper with arguments (7,) and {}
Calling wrapper with arguments (6,) and {}
Calling wrapper with arguments (5,) and {}
Calling wrapper with arguments (4,) and {}
Calling wrapper with arguments (3,) and {}
Calling wrapper with arguments (2,) and {}
Returning 1 from wrapper
Returning 0 from wrapper
Returning 1 from wrapper
Calling wrapper with arguments (1,) and {}
Calling wrapper with arguments (0,) and {}
Returning 1 from wrapper
Returning 2 from wrapper
Calling wrapper with arguments (1,) and {}
Calling wrapper with arguments (0,) and {}
Returning 1 from wrapper
Returning 3 from wrapper
Calling wrapper with arguments (2,) and {}
Calling wrapper with arguments (1,) and {}
Calling wrapper with arguments (0,) and {}
Returning 2 from wrapper
Returning 5 from wrapper
```

4.带有参数的装饰器

有时,您可能需要在一个装饰器中传递参数。例如,您可能希望使装饰器只记录特定的函数参数。在这种情况下,您可以定义一个装饰器函数,并将参数传递给它。然后,您可以通过将装饰器函数返回装饰器本身来创建一个实际的装饰器。

以下是一个示例,其中定义了一个名为“log_calls_with”的装饰器函数,该函数接受一个参数“arg”,并返回一个装饰器函数,该函数记录特定参数的函数调用:

```
def log_calls_with(arg):
    def log_calls(func):
        def wrapper(*args, **kwargs):
            if arg in args or arg in kwargs:
                print("Calling {} with arguments {} and {}".format(func.__name__, args, kwargs))
            result = func(*args, **kwargs)
            print("Returning {} from {}".format(result, func.__name__))
            return result
        return wrapper
    return log_calls

@log_calls_with(2)
def add(x, y):
    return x + y

result = add(2, 3)
print(result)

result = add(4, 5)
print(result)
```

在上面的代码中,我们定义了一个名为“log_calls_with”的装饰器函数,它接受一个参数“arg”,并返回一个名为“log_calls”的装饰器函数。这个装饰器函数记录包含“arg”参数的函数调用。我们然后使用“@”符号将“log_calls_with”应用于函数“add”,并指定“arg”参数为“2”。

当我们运行以上代码,输出如下:

```
Calling add with arguments (2, 3) and {}
Returning 5 from add
5
Calling add with arguments (4, 5) and {}
Returning 9 from add
9
```

本文中我们学习了Python中装饰器的定义、语法和多个装饰器、带有参数的装饰器的应用,其应用范围还远不于此。装饰器是Python中一个非常强大的工具,能够帮助我们写出更优雅、模块化和可维护的代码。