Python中的装饰器

Python中的装饰器

Python中的装饰器

装饰器是Python中一个非常重要且强大的概念,它可以在不修改原函数代码的情况下,动态地扩展函数的功能。在Python中,函数本身也是对象,因此我们可以像操作普通对象一样来操作函数,比如赋值给变量、作为参数传递等。装饰器实际上就是一个闭包函数,它接受一个函数作为参数,并返回一个新的函数。当我们在定义一个函数时,在函数的上方添加 @decorator 这样的语法糖,就能够使用装饰器来对函数进行装饰。

装饰器的基本用法

下面我们来看一个简单的装饰器的示例:

def hello_decorator(func):
    def wrapper():
        print("Before function execution")
        func()
        print("After function execution")
    return wrapper

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

say_hello()
Python

运行上面的代码,输出如下:

Before function execution
Hello, world!
After function execution
Python

在这个示例中,我们定义了一个装饰器函数 hello_decorator,它接受一个函数作为参数,并返回一个新的函数 wrapper。在 wrapper 函数中,我们首先打印一段信息,然后调用原始函数,最后再打印一段信息。在调用 say_hello 函数时,实际上是调用了被装饰后的函数。

带参数的装饰器

有时候我们需要给装饰器传递参数,例如我们想指定打印的信息。下面是一个带参数的装饰器的示例:

def decorator_with_args(message):
    def real_decorator(func):
        def wrapper():
            print(f"Before function execution: {message}")
            func()
            print(f"After function execution: {message}")
        return wrapper
    return real_decorator

@decorator_with_args("Decoration message")
def say_hello():
    print("Hello, world!")

say_hello()
Python

运行上面的代码,输出如下:

Before function execution: Decoration message
Hello, world!
After function execution: Decoration message
Python

在这个示例中,我们定义了一个带参数的装饰器 decorator_with_args,它接受一个参数 message,并返回一个装饰器函数 real_decorator。在 real_decorator 函数中,我们可以访问传递进来的参数,并在 wrapper 函数中使用。然后可以像普通装饰器一样使用这个带参数的装饰器。

类装饰器

除了函数装饰器外,Python还支持类装饰器。类装饰器是一个类,它必须实现 __call__ 方法,并在这个方法中实现装饰器的逻辑。下面是一个类装饰器的示例:

class DecoratorClass:
    def __init__(self, func):
        self.func = func

    def __call__(self):
        print("Before function execution")
        self.func()
        print("After function execution")

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

say_hello()
Python

运行上面的代码,输出如下:

Before function execution
Hello, world!
After function execution
Python

在这个示例中,我们定义了一个类 DecoratorClass,它接受一个函数作为参数,并在 __call__ 方法中实现装饰器的逻辑。然后将函数 say_hello 使用类装饰器 DecoratorClass 进行装饰。

多个装饰器

在Python中,一个函数可以被多个装饰器装饰。装饰器的执行顺序是从下往上执行,即最后装饰的最先执行。下面是一个使用多个装饰器的示例:

def decorator1(func):
    def wrapper():
        print("Decorator 1 - Before function execution")
        func()
        print("Decorator 1 - After function execution")
    return wrapper

def decorator2(func):
    def wrapper():
        print("Decorator 2 - Before function execution")
        func()
        print("Decorator 2 - After function execution")
    return wrapper

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

say_hello()
Python

运行上面的代码,输出如下:

Decorator 1 - Before function execution
Decorator 2 - Before function execution
Hello, world!
Decorator 2 - After function execution
Decorator 1 - After function execution
Python

在这个示例中,我们定义了两个装饰器 decorator1decorator2,然后将它们分别装饰在 say_hello 函数上。由于装饰器的执行顺序是从下往上执行,所以 decorator2 先执行,然后是 decorator1

带参数的类装饰器

类装饰器也可以带参数,只需要在类初始化时接受参数即可。下面是一个带参数的类装饰器的示例:

class DecoratorClassWithArgs:
    def __init__(self, message):
        self.message = message

    def __call__(self, func):
        def wrapper():
            print(f"Before function execution: {self.message}")
            func()
            print(f"After function execution: {self.message}")
        return wrapper

@DecoratorClassWithArgs("Decoration message")
def say_hello():
    print("Hello, world!")

say_hello()
Python

运行上面的代码,输出如下:

Before function execution: Decoration message
Hello, world!
After function execution: Decoration message
Python

在这个示例中,我们定义了一个带参数的类装饰器 DecoratorClassWithArgs,在初始化时接受参数 message。然后在 __call__ 方法中实现装饰器的逻辑。最后将函数 say_hello 使用带参数的类装饰器装饰。

functools.wraps装饰器

在定义装饰器时,如果不加 functools.wraps 装饰器,原函数的元信息(如函数名、文档字符串)会丢失。为了保留原函数的元信息,我们可以在内部函数中使用 functools.wraps 装饰器。下面是一个示例:

import functools

def my_decorator(func):
    @functools.wraps(func)
    def wrapper():
        """This is a wrapper function"""
        print("Before function execution")
        func()
        print("After function execution")
    return wrapper

@my_decorator
def say_hello():
    """This is the original function"""
    print("Hello, world!")

say_hello()
print(say_hello.__name__)
print(say_hello.__doc__)
Python

运行上面的代码,输出如下:

Before function execution
Hello, world!
After function execution
say_hello
This is the original function
Python

在这个示例中,我们在 wrapper 函数中使用 functools.wraps(func) 装饰器来保留原函数 say_hello的元信息。这样做可以确保装饰器不会影响原函数的属性。

带参数的装饰器

有时候我们需要给装饰器传递参数,并且这些参数可能会影响装饰器的行为。下面是一个带参数的装饰器的示例:

def parametrized_decorator(param1, param2):
    def real_decorator(func):
        def wrapper():
            print(f"Decorator parameters: {param1}, {param2}")
            func()
        return wrapper
    return real_decorator

@parametrized_decorator("Param1", "Param2")
def say_hello():
    print("Hello, world!")

say_hello()
Python

运行上面的代码,输出如下:

Decorator parameters: Param1, Param2
Hello, world!
Python

在这个示例中,我们定义了一个带参数的装饰器 parametrized_decorator,它接受两个参数,并返回一个装饰器函数 real_decorator。在 real_decorator 函数中,我们可以访问传递进来的参数,并在 wrapper 函数中使用。

装饰器的应用场景

装饰器在Python中有着广泛的应用场景,比如日志记录、性能测试、缓存、权限验证等。下面是一个使用装饰器记录函数执行时间的示例:

import time

def performance_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Function {func.__name__} executed in {(end_time - start_time):.2f} seconds")
        return result
    return wrapper

@performance_decorator
def time_consuming_function():
    time.sleep(2)
    print("Function executed!")

time_consuming_function()
Python

运行上面的代码,输出如下:

Function executed!
Function time_consuming_function executed in 2.00 seconds
Python

在这个示例中,我们定义了一个装饰器 performance_decorator,它记录了函数执行的时间。将 time_consuming_function 使用装饰器装饰后,可以方便地获取函数执行的时间。

总结

装饰器是Python中非常强大和灵活的功能,可以用来动态地扩展函数的功能,而不需要改变原函数的代码。通过装饰器,我们可以实现很多功能,比如日志记录、性能测试、权限验证等。掌握装饰器的使用方法可以让我们写出更加优雅和灵活的代码。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程

登录

注册