Code - Python 装饰器示例

核心知识点

- 装饰器本质:函数嵌套+闭包,用于增强函数功能且不修改原函数代码(解耦)
- 基础语法:@装饰器名 修饰函数,等价于 原函数 = 装饰器名(原函数)
- 带参数的装饰器:需额外嵌套一层函数接收参数,适配不同场景需求
- 企业常用场景:日志记录、接口限流、权限校验(对标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中为接口添加的“日志中间件”,无需在每个接口函数内重复编写日志代码,只需通过注解/配置挂载中间件,实现功能复用,符合“开闭原则”。

添加新评论