欢迎访问宙启技术站
智能推送

Python中的装饰器是什么,如何使用?

发布时间:2023-06-26 19:24:08

Python中的装饰器是一种高级的功能,它可以让我们在不改变原函数的情况下,对其进行扩展和修改。装饰器本质上是一个Python函数或类,它可以监听、修改或包装其他函数或类。

当我们需要在一个函数或类执行之前或之后添加一些额外的功能时,可以使用装饰器来完成这个目标。比如,我们可以通过装饰器来记录函数执行时间、记录函数调用次数、给函数添加缓存、验证函数参数、验证函数返回值等。

在Python中,我们可以使用“@装饰器函数名”或“@装饰器类名”的语法来应用装饰器。这个语法会把装饰器作用于函数或类上。比如,下面的代码演示了如何使用装饰器来记录函数执行时间:

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print("函数 {}() 的执行时间为 {:.6f} 秒。".format(func.__name__, end_time - start_time))
        return result
    return wrapper

@timer
def foo():
    time.sleep(1)

foo()

在上面的代码中,我们先定义了一个名为timer的装饰器函数。这个函数接收一个函数对象作为参数,并返回一个inner函数。inner函数实现了记录函数执行时间的功能,它先记录函数开始执行的时间,然后调用原函数,最后再记录函数执行结束的时间,并计算出执行时间。最后,inner函数返回原函数的执行结果。

我们然后在函数定义上方添加了“@timer”语法,来应用timer装饰器函数。这样,原来的foo函数就被timer装饰器函数“包装”了一下,变成了inner函数。当我们调用foo函数时,其实是调用inner函数,inner函数又会执行原来的foo函数,并在执行前后记录了函数执行时间。

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

函数 foo() 的执行时间为 1.001373 秒。

可以看到,foo函数执行了1秒,而我们通过装饰器函数timer记录了这个时间。

除了函数装饰器,Python还支持类装饰器。类装饰器的实现和函数装饰器类似,只不过它接收的是一个类对象作为参数,并返回一个新的类对象。比如,下面的代码演示了如何使用类装饰器来统计类方法的调用次数:

class CountCalls:
    def __init__(self, func):
        self._func = func
        self._count = 0

    def __call__(self, *args, **kwargs):
        self._count += 1
        print("函数 {}() 已被调用 {} 次。".format(self._func.__name__, self._count))
        return self._func(*args, **kwargs)

@CountCalls
def foo():
    print("Hello")

foo()
foo()
foo()

在上面的代码中,我们定义了一个名为CountCalls的类装饰器。这个装饰器接收一个函数对象作为参数,并返回一个新的类对象。我们在类的构造函数中,保存原函数对象和调用次数的变量。在类的__call__()方法中,统计调用次数,并输出到控制台,然后再调用原函数。

然后,我们在函数定义上方添加了“@CountCalls”语法,来应用CountCalls装饰器类。当我们调用foo函数时,它会自动调用CountCalls实例的__call__()方法,并在控制台输出函数调用次数的信息。

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

函数 foo() 已被调用 1 次。
Hello
函数 foo() 已被调用 2 次。
Hello
函数 foo() 已被调用 3 次。
Hello

可以看到,我们通过类装饰器CountCalls,成功统计了foo函数的调用次数。

在实际开发中,装饰器是一个非常强大的工具,它可以帮助我们写出更简洁、更易读、更可维护的代码。使用装饰器,我们可以轻松地实现横切关注点(cross-cutting concerns)的功能,而不需要修改原函数或类的代码。在日常开发中,我们经常会用到各种各样的装饰器,比如缓存装饰器、异常处理装饰器、输入输出参数验证装饰器、授权访问装饰器等。熟练掌握装饰器相关知识,对于成为一名优秀的Python开发者是非常重要的。