• 周五. 4月 19th, 2024

Python 装饰器的详细使用方法

城主

12月 26, 2022 ,

装饰器是一种在不修改函数的前提下为函数增加额外功能的机制。它是通过在函数前面加上一个装饰器函数来实现的。

举个例子,假设我们有一个函数 say_hello,它打印出 “Hello, world!”。我们希望在这个函数执行之前和之后都能打印一条消息。

我们可以使用装饰器来实现这个功能:





def logger(func):
    def wrapper(*args, **kwargs):
        print("Before calling function")
        result = func(*args, **kwargs)
        print("After calling function")
        return result
    return wrapper

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

say_hello()

输出结果如下:





Before calling function
Hello, world!
After calling function

我们可以看到,在调用 say_hello 函数之前和之后都有一条消息被打印出来。这就是装饰器的作用。

装饰器的语法是在函数定义之前加上一个 @decorator 语句,其中 decorator 是装饰器函数的名称。在这个例子中,我们使用了 @logger 装饰器,它会在函数被调用之前和之后打印消息。

装饰器是一种非常有用的工具,它可以让我们在不修改函数的情况下为函数增加额外的功能。它们常用于日志记录、权限检查和其他类似的场景。

装饰器可以接受参数,例如:





def logger(prefix):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(prefix, "Before calling function")
            result = func(*args, **kwargs)
            print(prefix, "After calling function")
            return result
        return wrapper
    return decorator

@logger("DEBUG")
def say_hello():
    print("Hello, world!")

say_hello()

输出结果如下:





DEBUG Before calling function
Hello, world!
DEBUG After calling function

可以看到,我们在装饰器函数 logger 中传入了一个参数 prefix,然后在装饰器内部的包装函数 wrapper 中使用了这个参数。这样,我们就可以根据需要在装饰器中使用参数了。

阅读  python保存jupyter notebook 代码为.py格式

装饰器还有一个常见的用法是将它们嵌套使用。例如,我们可以定义一个装饰器 decorator_a,然后在这个装饰器的内部使用另一个装饰器 decorator_b

例如:





def decorator_a(func):
    def wrapper(*args, **kwargs):
        print("Decorator A")
        return func(*args, **kwargs)
    return wrapper

def decorator_b(func):
    def wrapper(*args, **kwargs):
        print("Decorator B")
        return func(*args, **kwargs)
    return wrapper

@decorator_a
@decorator_b
def say_hello():
    print("Hello, world!")

say_hello()

输出结果如下:





Decorator B
Decorator A
Hello, world!

可以看到,当我们调用 say_hello 函数时,两个装饰器都会执行。这样,我们就可以使用嵌套的装饰器来扩展函数的功能。

装饰器还可以通过使用 functools.wraps 函数来保留原函数的元信息,例如函数名称、文档字符串和参数列表等。这样,在使用装饰器修饰函数之后,函数的元信息仍然是正确的。

例如:





import functools

def logger(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print("Before calling function")
        result = func(*args, **kwargs)
        print("After calling function")
        return result
    return wrapper

@logger
def say_hello():
    """Say hello to the world"""
    print("Hello, world!")

print(say_hello.__name__)  # Outputs: "say_hello"
print(say_hello.__doc__)   # Outputs: "Say hello to the world"

可以看到,使用了 functools.wraps 函数之后,函数的名称和文档字符串仍然是正确的。这样,我们就可以在使用装饰器的同时保留原函数的元信息了。

阅读  Python 中操作 Microsoft Excel 表格

在 Python 中,装饰器也可以用于类。例如,我们可以定义一个装饰器,在类定义之前使用它来修改类的属性或方法。

例如:





def logger(cls):
    cls.logged = True
    return cls

@logger
class MyClass:
    def __init__(self, value):
        self.value = value

obj = MyClass(42)
print(obj.logged)  # Outputs: True

在这个例子中,我们定义了一个装饰器 logger,它会在类定义之前修改类的 logged 属性。然后,我们使用了 @logger 装饰器来修饰类 MyClass。这样,在创建 MyClass 的实例时,这个实例就会具有 logged 属性。

同样的,我们也可以在装饰器中使用参数,例如:





def logger(prefix):
    def decorator(cls):
        cls.logged = True
        cls.prefix = prefix
        return cls
    return decorator

@logger("DEBUG")
class MyClass:
    def __init__(self, value):
        self.value = value

obj = MyClass(42)
print(obj.logged)    # Outputs: True
print(obj.prefix)    # Outputs: "DEBUG"

在这个例子中,我们的装饰器可以接受一个参数 prefix,然后在装饰器内部使用这个参数来修改类的属性。这样,我们就可以在使用装饰器的同时传入参数了。

总的来说,装饰器是一种非常有用的工具,它可以帮助我们为函数增加额外的功能,同时还可以保留原函数的元信息。它们广泛应用于 Python 编程中,常用于日志记录、权限检查和其他类似的场景。