核心知识点
- 装饰器本质:函数嵌套+闭包,用于增强函数功能且不修改原函数代码(解耦)
- 基础语法:@装饰器名 修饰函数,等价于 原函数 = 装饰器名(原函数)
- 带参数的装饰器:需额外嵌套一层函数接收参数,适配不同场景需求
- 企业常用场景:日志记录、接口限流、权限校验(对标PHP的中间件机制)
实战案例:接口调用日志
案例需求
开发一个装饰器,为AI接口函数(如文本摘要、分类接口)添加调用日志,需记录:调用时间、函数名、传入参数、返回结果、调用耗时,日志保存到本地文件(api_logs.txt),格式规范易读。装饰器
实现步骤(可跟随操作)
1. 导入所需模块:time(获取时间)、functools(解决装饰器破坏原函数元信息问题)
2. 定义带参数的装饰器(支持指定日志文件路径)
3. 编写装饰器内部逻辑:记录开始时间→执行原函数→记录结束时间→计算耗时→写入日志
4. 定义测试接口函数(如模拟文本摘要接口),用装饰器修饰
5. 调用函数,验证日志生成效果
import re
import time
import functools
from cv2 import log
def api_logger(log_file="api_log.txt"):
"""
日志装饰器,用于记录函数的调用时间、参数和返回值。
:param log_file: 日志文件路径,默认值为"api_log.txt"。
:return: 装饰后的函数。
"""
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# 1. 记录调用时间(格式化:年-月-日 时:分:秒)
call_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
# 2. 记录函数名和传入参数
func_name = func.__name__
args_str = str(args)
kwargs_str = str(kwargs)
result = None
# 3. 执行原函数,获取返回结果(捕获可能的异常,避免函数报错导致日志丢失)
try:
start_time = time.time() # 开始时间戳
result = func(*args, **kwargs) # 执行函数
end_time = time.time() # 结束时间戳
cost_time = end_time - start_time # 耗时
log_level = "INFO" # 日志级别,正常调用
result_str = str(result)
except Exception as e:
end_time = time.time() # 结束时间戳
cost_time = end_time - start_time # 耗时
log_level = "ERROR" # 日志级别,异常调用
result_str = f"调用失败:{str(e)}"
result = f"调用失败:{str(e)}"
log_msg = f"{call_time} [{log_level}] 函数名:{func_name},参数:{args_str}{kwargs_str},耗时:{cost_time:.6f}秒,返回值:{result_str}"
with open(log_file, "a") as f:
f.write(log_msg + "\n")
return result
return wrapper
return decorator
@api_logger(log_file="ai_api_log.txt") # 使用装饰器,指定日志文件
def text_summary(text: str, max_len=100):
"""
对文本进行摘要,提取其中的主要内容。
:param text: 输入的文本。
:return: 摘要后的文本。
"""
# 简单的摘要实现,仅提取文本中的前100个字符
if not isinstance(text, str) or len(text) == 0:
raise ValueError("文本不能为空字符串")
summary = text[:max_len] + "..." if len(text) > max_len else text
return {"code": 200, "msg": "success", "data": summary}
# 调用测试
if __name__ == "__main__":
# 正常调用
x = text_summary(
"济南是山东省省会,也是环渤海地区南翼的中心城市,近年来在AI产业领域发展迅速,本地涌现出多家AI应用型企业,主要聚焦政务信息化、企业服务等方向。",
max_len=200,
)
print(x)
# # 异常调用(测试错误日志)
# err = text_summary("")
# print(err)验证方法
1. 运行代码后,查看当前目录下是否生成「ai_api_logs.txt」文件
2. 打开文件,检查日志格式是否符合预期,是否包含:级别、时间、函数名、参数、耗时、结果
3. 异常调用部分应记录ERROR级别,包含具体错误信息(文本不能为空字符串)
最后
PHP开发者对标理解
该装饰器等价于PHP中为接口添加的“日志中间件”,无需在每个接口函数内重复编写日志代码,只需通过注解/配置挂载中间件,实现功能复用,符合“开闭原则”。