1. 什么是Python的装饰器
Python的装饰器是一种函数,它可以修改其他函数的功能。在Python中,函数是一等对象,因此我们可以将函数作为参数传递给另一个函数,这给了我们在Python中使用装饰器的机会。
装饰器通常用于修改函数的行为或属性,例如缓存、日志记录、输入验证等。装饰器在Python中非常常见,并且被广泛应用于各种框架和库。
2. Python装饰器的基础语法
Python装饰器可以用@符号来表示。要使用装饰器,我们需要先定义它,然后将它应用到我们要修改的函数上。
2.1 装饰器的定义
def my_decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
在这个例子中,我们定义了一个名为my_decorator的装饰器。它接受一个函数作为参数,并返回另一个函数。
在这个例子中,我们返回了一个名为wrapper的函数,它接受任意数量的位置参数和关键字参数,并返回调用原始函数的结果。
2.2 装饰器的应用
@my_decorator
def my_function():
print("Hello, World!")
在这个例子中,我们定义了一个名为my_function的函数,并使用@my_decorator将其装饰。这与下面的语法等效:
my_function = my_decorator(my_function)
这意味着当我们调用my_function时,它实际上是调用了wrapper函数,因为my_function已经被装饰了。
3. 带参数的装饰器
装饰器还可以接受参数。它们具有与普通函数相同的语法,并将参数传递给包装函数。
3.1 带参数的装饰器的定义
def logger(log_level):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"[{log_level}] {func.__name__}被调用了。")
return func(*args, **kwargs)
return wrapper
return decorator
在这个例子中,我们定义了一个名为logger的装饰器,它接受一个参数log_level。然后,它返回另一个函数decorator,它接受一个参数func。decorator函数接着返回另一个函数wrapper,它接受任意数量的位置参数和关键字参数,并返回调用原始函数的结果。
在这个例子中,我们将log_level参数传递给了wrapper函数,以便它可以被记录下来。
3.2 带参数的装饰器的应用
@logger(log_level="DEBUG")
def my_function():
print("Hello, World!")
在这个例子中,我们使用@logger(log_level="DEBUG")来装饰my_function函数。这将使my_function被记录为“DEBUG”级别。
当我们调用my_function时,它实际上是调用了wrapper函数,因为my_function已经被装饰了。wrapper函数负责在函数调用前后记录日志。
3.3 带参数的装饰器的运行原理
当我们使用装饰器时,Python将调用decorator函数,并将my_function作为参数传递给它。decorator函数负责返回wrapper函数,该函数将被用于调用my_function。
因此,当我们调用my_function时,实际上是调用wrapper函数。wrapper函数负责记录日志,并调用原始的my_function。
3.4 为带参数的装饰器添加参数
装饰器可以递归附加上参数。这种方法也是在我们的装饰器基础上定义一个新的装饰器函数,使其能够接受要传递的参数。
def logger(log_level):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"[{log_level}] {func.__name__}被调用了。")
return func(*args, **kwargs)
return wrapper
return decorator
def wrapped_logger(fn=None, *, log_level='INFO'):
if fn is None:
return partial(wrapped_logger, log_level=log_level)
@wraps(fn)
@logger(log_level=log_level)
def wrapped(*args, **kwargs):
return fn(*args, **kwargs)
return wrapped
在这个例子中,我们定义了一个新的装饰器函数wrapped_logger。如果它没有传递任何参数,则它将返回一个partial函数(Python内置函数),用指定的日志级别调用wrapped_logger。
wrapped_logger函数也可以接受一个名为fn的参数,它是要装饰的函数。我们使用functools包中的wraps函数来保留原始函数的签名。
在这个例子中,我们将wrapped_logger包装在logger内部的decorator函数内。这将允许我们递归附加上参数。
当我们使用@wrapped_logger(log_level="DEBUG")装饰my_function时,它实际上是调用了wrapped_logger函数,并使用指定的参数创建了一个logger装饰器。然后,它将my_function传递给装饰器。
总之,通过这种方法,我们可以在使用装饰器时为其添加参数,同时保留装饰器的所有功能。