装饰器

装饰器本身是一种设计模式,Python中则基于这种设计模式提供了装饰器语法糖,它能在不改变函数本身的情况下扩展或增强函数的功能。装饰器本质上是一个高阶函数,它接受一个函数作为参数,并返回一个具有增强功能的新函数。

定义和使用装饰器

下面例子代码我们定义了一个装饰器@log,它在函数执行前和执行后分别打印一些信息。

from typing import Callable


def log(func: Callable) -> Callable:
    def wrapper(*args, **kwargs):
        print("Something is happening before the function is called.")
        result = func(*args, **kwargs)
        print("Something is happening after the function is called.")
        return result

    return wrapper


@log
def say_hello():
    print("Hello!")


@log
def bark(loop: int):
    for i in range(loop):
        print("bark!")


say_hello()
bark(3)

代码中装饰器的内部实际上定义了一个新的函数wrapper,它接收任意参数并将参数原样传给被装饰的func函数,wrapper函数内在调用func函数前后打印了一些信息,然后将func的返回值原样返回。

注意:上面代码中我们的装饰器@log还处理了参数和返回值,这使得它能够装饰任意函数,这让我们编写的装饰器更具通用性,这也是一种最佳实践。

带参数装饰器

Python的装饰器也可以是带有参数的,此时我们可以用一个三阶函数来实现带参数装饰器,下面是一个例子。

from typing import Callable


def repeat(times: int) -> Callable:
    def decorator(func: Callable) -> Callable:
        def wrapper(*args, **kwargs):
            for _ in range(times):
                func(*args, **kwargs)

        return wrapper

    return decorator


@repeat(3)
def say_hello():
    print("Hello, world!")


say_hello()

代码中我们自定义了@repeat装饰器,它可以将内部的函数重复执行若干次,我们可以发现它实际上还是一个闭包。

装饰器函数内部返回一个接收func参数的函数,该函数内部又返回一个接收任意参数的wrapper函数,wrapper函数内部重复执行被装饰的func函数。这里我们就没有处理被装饰函数的返回值了,因为它被多次调用,所以返回值没有太大意义,实际开发中我们可以根据实际情况来决定是否处理返回值。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。