Python中的装饰器是什么,如何使用?
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开发者是非常重要的。
