Python装饰器本质上是一个接受函数作为参数并返回一个新函数的高阶函数。这个特性使得装饰器成为改变函数行为的一种非常灵活的方式。让我们从一个简单的例子开始,来理解装饰器的基本结构。
def simple_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@simple_decorator
def say_hello():
print("Hello!")
say_hello()
在这个例子中,simple_decorator
就是一个装饰器,它接收一个函数func
作为参数,并定义了一个新的函数wrapper
来扩展func
的功能。当我们使用@simple_decorator
修饰say_hello
函数时,实际上是将say_hello
函数作为参数传递给了simple_decorator
,并且say_hello
函数被wrapper
函数替代。因此,当我们调用say_hello()
时,实际上是在调用wrapper()
。
接下来,我们来看看如何编写带参数的装饰器。这需要我们使用一个额外的函数来封装我们的装饰器,以便能够接收参数。
def decorator_with_args(arg):
def real_decorator(func):
def wrapper():
print(f"Decorator arg: {arg}")
func()
return wrapper
return real_decorator
@decorator_with_args("inside decorator")
def say_hello_again():
print("Hello again!")
say_hello_again()
在这个例子中,decorator_with_args
函数接收一个参数,并返回一个装饰器real_decorator
。这样我们就可以在装饰器中使用参数了。
装饰器还可以进行嵌套使用,这意味着我们可以在一个函数上使用多个装饰器,每个装饰器都会按照从内到外的顺序作用于函数。
最后,Python标准库中的functools
模块提供了一些用于优化装饰器的函数,其中最常用的是functools.wraps
,它可以帮助我们保持原函数的名称、文档字符串、注解等信息。
from functools import wraps
def better_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Before calling function")
result = func(*args, **kwargs)
print("After calling function")
return result
return wrapper
@better_decorator
def add(a, b):
"""Add two numbers"""
return a + b
print(add.__name__) # 输出 'add',而不是 'wrapper'
通过使用functools.wraps
,我们确保了即使函数被装饰器修改过,它的元信息仍然保持不变。
总结来说,Python装饰器是一个非常强大且灵活的工具,它允许我们在不修改原始函数定义的情况下增加额外的功能。从简单的函数包装到复杂的参数处理和嵌套装饰器,再到使用functools
进行性能优化,装饰器为Python编程提供了无限的可能性。通过掌握装饰器的使用,你将能够编写出更加优雅和高效的代码。