跳转至

Python 语言进阶 —— 装饰器

介绍

Python 中的装饰器是一种用于修改或增强函数(或方法)功能的设计模式。装饰器本质上是一个返回函数的高阶函数,可以在不修改原有函数代码的情况下,为其添加额外的功能。

装饰器本质上是一个函数,它接收一个函数作为参数并返回一个新的函数。这个新的函数就是对原有函数的一种包装或增强。这样可以使得在不改变原函数代码的前提下,给 原函数额外增加一些功能。

定义步骤

定义一个装饰器的步骤可以分成如下几步:

  1. 编写装饰器函数。首先,创建一个装饰器函数,该函数将另一个函数作为参数接收。
  2. 实现包装逻辑。在装饰器函数内部,定义一个包装函数(wrapper)。这个包装函数负责调用传入的原函数,并能够在调用前后插入额外的逻辑。
  3. 返回包装函数。装饰器函数应返回这个包装函数,以便替代原始函数的行为。
  4. 应用装饰器。在需要装饰的函数声明前,使用 @ 符号并指定装饰器的名称。这样,Python 解释器会自动将目标函数传递给装饰器,并用返回的包装函数替换原函数
# 1. 编写装饰器函数
def decorator_function(original_function):
    # 2. 实现包装逻辑
    def wrapper_function(*args, **kwargs):
        # 在这里可以添加功能
        print("Wrapper executed before {}".format(original_function.__name__))

        # 调用原函数
        result = original_function(*args, **kwargs)

        # 在这里可以添加功能
        print("Wrapper executed after {}".format(original_function.__name__))
        return result

    # 3. 返回包装函数
    return wrapper_function


# 4. 应用装饰器
@decorator_function
def say_hello(name):
    print("Hello, {}".format(name))


# 调用被装饰的函数
say_hello("Alice")

输出:

Wrapper executed before say_hello
Hello, Alice
Wrapper executed after say_hello

带参数的装饰器

当被修饰的函数需要参数时,装饰器中的包装函数可以通过*args**kwargs 接收这些参数。

def decorator(func):
    def wrapper(*args, **kwargs):
        print("Function is called with arguments:", args, kwargs)
        result = func(*args, **kwargs)
        return result

    return wrapper


@decorator
def my_function(x, y):
    return x + y


print(my_function(3, 4))

传递参数给装饰器

如果需要给装饰器本身传递参数,可以使用一个外层函数来封装装饰器。

def repeat(num_times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                result = func(*args, **kwargs)
            return result

        return wrapper

    return decorator


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


say_hello()  # 输出三次Hello!

保留原信息

在使用装饰器时,原函数的元信息(如函数名、文档字符串等)会被包装函数所替代。为了保留这些信息,可以使用 functools.wraps 装饰器。

from functools import wraps


def my_decorator(func):
    @wraps(func)
    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


@my_decorator
def example():
    """This is an example function."""
    print("Hello from a function.")


print(example.__doc__)  # 输出: This is an example function.