Python 装饰器是一种编程模式,用于修改或扩展函数或类的行为,而不需要修改它们的源代码。Python 装饰器通常使用 "@" 符号定义,并在函数或类声明的前面使用。
使用装饰器,您可以通过将装饰器函数或者装饰器类应用到函数或类上,改变它们的行为。常用的一些 Python 装饰器包括:缓存、日志、授权、计时和调试等。
下面是一个使用装饰器修改函数行为的简单示例:
def my_decorator(func):
def wrapper():
print("before")
func()
print("after")
return wrapper
@my_decorator
def hello():
print("Hello, World!")
hello()
在上例中,my_decorator
是一个装饰器函数,用于在函数调用前后打印一些内容。装饰器函数接收一个函数作为参数,然后返回一个新的函数 wrapper
,该函数用来调用原始函数并执行操作。
通过在 hello
函数定义前使用 @my_decorator
,我们将装饰器应用到了该函数上。这样,每次调用该函数时,都会首先打印 "before",然后调用 hello
函数,并打印 "after"。
输出结果如下:
before
Hello, World!
after
除了使用函数作为装饰器外,Python 还支持使用类作为装饰器。使用类作为装饰器时需要实现 __call__
方法,该方法接收函数作为参数,并返回一个新的函数。
下面是一个使用类作为装饰器的示例:
class MyDecorator:
def __init__(self, func):
self._func = func
def __call__(self):
print("before")
self._func()
print("after")
@MyDecorator
def hello():
print("Hello, World!")
hello()
在上述示例中,我们定义了一个名为 MyDecorator
的装饰器类。该类定义了两个方法: __init__
和 __call__
。__init__
方法用于初始化装饰器类,而 __call__
方法用于在调用被装饰函数之前和之后执行操作。
与函数装饰器类似,我们可以使用 @MyDecorator
应用装饰器类到函数上。每次调用该函数时,都会首先打印 "before",然后调用 hello
函数,并打印 "after"。
输出结果如下:
before
Hello, World!
after
Python 装饰器非常有用,因为它们可以在不修改现有代码的情况下改变函数或类的行为。Python 标准库以及许多流行的框架都使用了装饰器来提供各种支持,包括缓存、并发执行、验证和日志等。
Python 装饰器的细节和高级用法。
装饰器链
Python 装饰器可以像管道一样连接起来,形成一个“装饰器链”。例如:
def make_bold(func):
def wrapper():
return "<b>" + func() + "</b>"
return wrapper
def make_italic(func):
def wrapper():
return "<i>" + func() + "</i>"
return wrapper
@make_bold
@make_italic
def hello():
return "Hello, World!"
print(hello())
在上述示例中,我们定义了两个装饰器 make_bold
和 make_italic
,它们分别用于添加 HTML 的加粗(bold)和斜体(italic)标签。
然后,在 hello
函数定义前使用了两个装饰器 @make_bold
和 @make_italic
,这意味着 hello
函数将首先被 make_bold
装饰器包裹,然后再由 make_italic
装饰器包裹。因此,在调用 hello
函数时,会首先添加斜体标签,然后再添加加粗标签,最终输出结果为:
<b><i>Hello, World!</i></b>
装饰器带参数
装饰器可以使用参数,这样可以让它们更加灵活。如果希望在运行时根据一些条件调整装饰器行为,那么这是非常有用的。
下面是一个带参数的装饰器示例:
def my_decorator(str_arg):
def decorate(func):
def wrapper():
print("doing something before " + str_arg)
func()
print("doing something after " + str_arg)
return wrapper
return decorate
@my_decorator("decorated string")
def hello():
print("Hello, World!")
hello()
在上例中,my_decorator
函数以参数形式接收一个字符串,然后返回另一个函数 decorate
。decorate
函数以函数作为参数,并返回新的 wrapper
函数。在 wrapper
函数中,我们使用在调用被装饰函数之前和之后打印字符串。
我们可以通过向装饰器传递不同的字符串参数来更改装饰器行为。
因此,我们通过在装饰器名称 @my_decorator
后面添加字符串参数,将该字符串参数传递到装饰器中。
输出结果如下:
doing something before decorated string
Hello, World!
doing something after decorated string
带有状态的装饰器
装饰器本身也可以具有状态,这意味着它们可以跟踪内部变量的值。
下面是一个带有状态的装饰器示例:
def count_decorator(func):
def wrapper():
wrapper.count += 1
func()
print("Count = ", wrapper.count)
wrapper.count = 0
return wrapper
@count_decorator
def hello():
print("Hello, World!")
hello()
hello()
hello()
在上例中,通过在 wrapper
函数上创建一个名称为 count
的属性来为装饰器添加状态。在每次调用被装饰的函数时,该属性将自增,值将传递给被打印到控制台的输出字符串。
当我们调用 hello
函数时,我们实际上调用了 wrapper
函数。每次调用 wrapper
函数会增加一个计数