Python的装饰器
一、装饰器的基本概念
- 定义
在 Python 中,装饰器(Decorator)是一种特殊的函数,它可以用于修改其他函数的功能。装饰器本质上是一个返回函数的高阶函数,它接受一个函数作为参数,并返回一个新的函数,这个新函数通常会在原函数的基础上添加一些额外的功能,如日志记录、性能测试、权限验证等。
- 示例
假设我们有一个简单的函数func,我们想要在调用这个函数时记录一些信息,比如函数被调用的时间。我们可以定义一个装饰器来实现这个功能。
import time
def log_time(func):
def wrapper():
start_time = time.time()
func()
end_time = time.time()
print(f"函数 {func.__name__} 执行时间为: {end_time - start_time}秒")
return wrapper
def func():
print("这是原函数")
time.sleep(2)
func = log_time(func)
func()
在这个例子中,log_time就是一个装饰器函数。它接受一个函数func作为参数,然后在内部定义了一个新的函数wrapper。这个wrapper函数会在调用原函数func之前记录开始时间,调用func之后记录结束时间,然后计算并打印出函数的执行时间。最后,装饰器函数返回wrapper函数。通过func = log_time(func)这一行,我们将原函数func替换为了经过装饰器修饰后的函数。当我们最后调用func()时,实际上调用的是wrapper()函数,从而实现了在原函数基础上添加记录执行时间的功能。
二、装饰器的语法糖
- 语法糖介绍
使用@符号是 Python 提供的装饰器语法糖,可以让装饰器的使用更加简洁。上面的例子可以改写为:
import time
def log_time(func):
def wrapper():
start_time = time.time()
func()
end_time = time.time()
print(f"函数 {func.__name__} 执行时间为: {end_time - start_time}秒")
return wrapper
@log_time
def func():
print("这是原函数")
time.sleep(2)
func()
当在函数定义前加上@log_time时,就相当于执行了func = log_time(func)这一步骤,使得代码更加简洁易读。
三、装饰器的参数传递
- 带有参数的函数的装饰
如果被装饰的函数带有参数,那么装饰器内部的wrapper函数也需要接收这些参数。例如,我们有一个函数add_numbers,它接受两个参数并返回它们的和。
def log_time(func):
def wrapper(x, y):
start_time = time.time()
result = func(x, y)
end_time = time.time()
print(f"函数 {func.__name__} 执行时间为: {end_time - start_time}秒")
return result
return wrapper
@log_time
def add_numbers(x, y):
return x + y
print(add_numbers(3, 5))
在这个例子中,wrapper函数接收了x和y两个参数,然后将它们传递给原函数func,并获取返回结果。最后,wrapper函数返回这个结果,并且在计算执行时间后打印出来。
- 装饰器本身带参数的情况
有时候,我们可能希望装饰器本身也可以接收参数,来实现更加灵活的功能。例如,我们想要一个可以根据不同的日志级别来记录日志的装饰器。
import logging
def log_with_level(level):
def decorator(func):
def wrapper(*args, **kwargs):
if level == "DEBUG":
logging.basicConfig(level = logging.DEBUG)
elif level == "INFO":
logging.basicConfig(level = logging.INFO)
# 其他级别设置
result = func(*args, **kwargs)
logging.log(getattr(logging, level), f"函数 {func.__name__} 被调用")
return result
return wrapper
return decorator
@log_with_level("INFO")
def another_function():
print("这是另一个函数")
another_function()
在这个例子中,log_with_level是一个外层函数,它接收一个日志级别参数level。它返回一个装饰器函数decorator,这个装饰器函数接受一个函数func作为参数,并返回wrapper函数。wrapper函数根据传入的日志级别进行日志配置,调用原函数func,记录日志,然后返回结果。通过@log_with_level("INFO")这样的语法,我们可以为不同的函数指定不同的日志级别进行装饰。