Python 中的装饰器
在 Python 中,装饰器是一种非常强大的功能,它允许你在不修改原有函数定义的情况下增加函数的功能。装饰器通常用于日志记录、性能测试、事务处理、缓存、权限校验等场景。
1.基本装饰器
一个装饰器本质上是一个 Python 函数,它可以接受一个函数作为参数并返回一个新的函数。让我们从最简单的装饰器开始:
def my_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
@my_decorator
def say_hello():
print("Hello!")
say_hello()
输出将会是:
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
在这个例子中,my_decorator
是一个装饰器,它内部定义了一个 wrapper
函数。wrapper
函数会在 func
被调用前后打印一些信息。通过在 say_hello
函数前面加上 @my_decorator
,我们实际上是将 say_hello
函数传递给了 my_decorator
,并将返回的 wrapper
函数赋值给 say_hello
。
2. 装饰器接受参数
如果你的函数需要接受参数,装饰器需要相应地进行调整:
def my_decorator(func):
def wrapper(*args, **kwargs):
print("Something is happening before the function is called.")
func(*args, **kwargs)
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say(message):
print(message)
say("Hello with argument")
在这个例子中,wrapper
函数使用 *args
和 **kwargs
来接受任意数量的位置参数和关键字参数,并将它们传递给 func
函数。
3.装饰器带有自己的参数
装饰器也可以带有自己的参数,这需要使用一个额外的函数层来接受这些参数:
def repeat(number_of_times):
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(number_of_times):
func(*args, **kwargs)
return wrapper
return decorator_repeat
@repeat(number_of_times=3)
def say(message):
print(message)
say("Hello repeated")
在这个例子中,repeat
函数是一个装饰器工厂,它创建并返回一个装饰器。这个装饰器接受一个函数并返回 wrapper
函数。wrapper
函数将会重复调用 func
函数指定的次数。
4.使用 functools.wraps
当你使用装饰器时,你实际上是用另一个函数 wrapper
替换了原始的函数。这意味着原始函数的一些信息,如它的名字、文档字符串、注解和模块信息会丢失。为了避免这种情况,你可以使用 functools.wraps
,它会保留原始函数的信息:
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""Wrapper function"""
print("Something is happening before the function is called.")
func(*args, **kwargs)
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_hello():
"""Say hello function"""
print("Hello!")
print(say_hello.__name__) # 输出 "say_hello"
print(say_hello.__doc__) # 输出 "Say hello function"
通过使用 functools.wraps
,say_hello
函数保留了它的元数据,而不是显示 wrapper
函数的元数据。
装饰器是 Python 中一个非常强大的特性,可以用来简洁地修改函数的行为。通过掌握装饰器,你可以编写出更加干净、优雅和可复用的代码。
拓展: 可变参数:*args
和 **kwargs
在 Python 中,*args
和 **kwargs
是处理函数可变参数的特殊语法。
*args
(arguments 的缩写)允许函数接收不确定数量的位置参数
。这些参数在函数内部被视为一个元组。**kwargs
(keyword arguments 的缩写)允许函数接收不确定数量的`关键字参数。这些参数在函数内部被视为一个字典。
使用 *args
和 **kwargs
的例子
def my_function(*args, **kwargs):
print("args:", args)
print("kwargs:", kwargs)
my_function(1, 2, 3, name="John", age=25)
输出:
args: (1, 2, 3)
kwargs: {'name': 'John', 'age': 25}
在装饰器中使用 *args
和 **kwargs
*args
和 **kwargs
在装饰器中非常有用,因为它们允许 wrapper
函数传递任意数量的参数给被装饰的函数。
下面是一个使用 *args
和 **kwargs
的装饰器示例:
def my_decorator(func):
def wrapper(*args, **kwargs):
# 在原始函数调用前做一些事情
result = func(*args, **kwargs)
# 在原始函数调用后做一些事情
return result
return wrapper
这个装饰器中的 wrapper
函数可以接收任意数量的位置参数和关键字参数,并将它们传递给被装饰的函数 func
。这样,不管 func
需要哪些参数,wrapper
都能正确地传递这些参数。