1. 了解装饰器的定义
在 Python 编程语言中,装饰器是一种可调用对象,其作用是 将其他函数进行包装,从而以某种方式修改其行为。通常,装饰器在不修改原始函数的源代码的情况下添加、改变或删除一些行为。 将装饰器应用于代码的过程称为装饰。装饰器的使用可以通过许多方式来理解,其中 一种将其视为“元编程”工具。
为方便后续代码演示,这里给出一个简单的示例函数:
def hello_world():
return "Hello, World!"
2. 装饰器的支持机制
在 Python 中,装饰器是基于闭包和函数作为“第一类对象”的机制支持。Python 中的函数是“第一类对象”,这意味着它们可以作为参数、作为函数的返回值、被赋值给变量等。而闭包则是指仅在其局部作用域内访问的函数和该函数引用的不属于全局命名空间的变量的结合。
下面的代码演示了一个闭包方案的例子:
def my_decorator(func):
def wrapper():
print("Wrapper function started")
func()
print("Wrapper function ended")
return wrapper
def say_hello():
print("Hello!")
decorated_say_hello = my_decorator(say_hello)
decorated_say_hello()
在此示例中,say_hello()
函数定义为常规函数,并定义了一个名为my_decorator
的函数,其取一个函数作为参数并返回另一个函数。 这个返回的函数是闭包,由两个部分组成:一个外部包装器函数和一个内部原始函数。 外部包装器函数在内部原始函数的前后执行一些操作,并返回原始函数的结果。
这里定义了名为decorated_say_hello
的变量,该变量引用wrapper()
函数,即装饰器处理say_hello()
后的结果。
3. 使用 @ 语法糖来使用装饰器
由于使用装饰器的常见操作,因此 Python 提供了在函数上使用装饰器时使用的 @ 符号(读作“pie”)简写,其中装饰器是跟随在 @ 符号后的,如下所示:
@my_decorator
def say_hello():
print("Hello!")
say_hello()
这样使用装饰器可以在代码中更加简单明了地定义使用装饰器的函数。
4. 装饰器可以接收参数
装饰器也可以接受参数,因为如上所述,装饰器实际上是一个函数,因此它可以接受参数。 这些参数可以传递给装饰器的包装器内部函数,例如:
def repeat(num):
def my_decorator(func):
def wrapper():
for i in range(num):
print("Wrapper function: ",i+1)
func()
return wrapper
return my_decorator
@repeat(num=3)
def say_hello():
print("Hello!")
say_hello()
这个简单的例子使用一个接受参数的装饰器将函数say_hello()
的执行重复了三次。
5. 装饰器是透明的
装饰器应用于函数时是透明的,因为在装饰后,函数的名称,注释,文档字符串及其参数签名都保持不变。下面的部分演示了装饰器是如何透明运作的:
import functools
def my_decorator(func):
@functools.wraps(func)
def wrapper():
print("Wrapper function started")
func()
print("Wrapper function ended")
return wrapper
@my_decorator
def say_hello():
"""This is a docstring for the function"""
print("Hello!")
print(say_hello.__name__) # prints "say_hello"
print(say_hello.__doc__) # prints "This is a docstring for the function"
在这个示例中,装饰器使用了 functools 包中的 functools.wraps()
函数。 在将functools.wraps()
应用于装饰器返回的包装器函数时,将其复制回原始函数的名称,注释和签名等信息。
6. 装饰器链
可以在一个函数上应用多个装饰器,形成所谓的 装饰器链或 堆栈,并通过将它们依次应用于原始函数来使用它们:
def my_decorator_1(func):
def wrapper():
print("Decorator 1 started")
func()
print("Decorator 1 ended")
return wrapper
def my_decorator_2(func):
def wrapper():
print("Decorator 2 started")
func()
print("Decorator 2 ended")
return wrapper
@my_decorator_1
@my_decorator_2
def say_hello():
print("Hello!")
say_hello()
这个例子演示了两个不同的装饰器如何应用于一个函数。它还演示了装饰器应用的顺序——在这个例子中,先应用了装饰器 2 和 后应用了装饰器 1来装饰 say_hello()
函数。
7. 总结
通过本文,你应该能够更好地了解,装饰器是如何在 Python 中工作和实现的。装饰器通过将其他函数进行包装,添加、改变或删除一些行为来修改其行为,从而可以很好地简化代码。如果你希望更好地了解装饰器的工作原理,可以进一步研究 Python 的闭包和函数作为“第一类对象”的支持机制。