当前位置: 首页 > news >正文

Python装饰器高级模式:从日志到AOP的完整实现

Python装饰器高级模式:从日志到AOP的完整实现

作者:Crown_22 | AI Agent & Hermes Agent 桌面程序开发者

前言

装饰器是Python中最优雅的特性之一,但大多数开发者只停留在@property@staticmethod的基础用法。实际上,装饰器可以实现日志、缓存、重试、权限控制、性能监控等众多高级功能。

本文将从装饰器的原理出发,逐步深入到高级模式,最终实现一个完整的AOP(面向切面编程)框架。


一、装饰器基础回顾

1.1 最简单的装饰器

defmy_decorator(func):defwrapper(*args,**kwargs):print("Before call")result=func(*args,**kwargs)print("After call")returnresultreturnwrapper@my_decoratordefsay_hello():print("Hello!")say_hello()# 输出:# Before call# Hello!# After call

1.2 带参数的装饰器

defrepeat(n):defdecorator(func):defwrapper(*args,**kwargs):for_inrange(n):result=func(*args,**kwargs)returnresultreturnwrapperreturndecorator@repeat(3)defgreet(name):print(f"Hello,{name}!")greet("World")# 输出:# Hello, World!# Hello, World!# Hello, World!

1.3 类装饰器

classLogger:def__init__(self,func):self.func=funcdef__call__(self,*args,**kwargs):print(f"Calling{self.func.__name__}")result=self.func(*args,**kwargs)print(f"Finished{self.func.__name__}")returnresult@Loggerdefadd(a,b):returna+bprint(add(1,2))# 输出:# Calling add# Finished add# 3

二、保留原函数信息

2.1 问题:装饰器丢失元信息

defmy_decorator(func):defwrapper(*args,**kwargs):returnfunc(*args,**kwargs)returnwrapper@my_decoratordefexample():"""这是文档字符串"""passprint(example.__name__)# 输出: wrapper(错误!)print(example.__doc__)# 输出: None(错误!)

2.2 解决方案:使用functools.wraps

fromfunctoolsimportwrapsdefmy_decorator(func):@wraps(func)defwrapper(*args,**kwargs):returnfunc(*args,**kwargs)returnwrapper@my_decoratordefexample():"""这是文档字符串"""passprint(example.__name__)# 输出: example(正确!)print(example.__doc__)# 输出: 这是文档字符串(正确!)

2.3 最佳实践:始终使用@wraps

fromfunctoolsimportwrapsfromtypingimportAny,Callable,TypeVar F=TypeVar('F',bound=Callable[...,Any])defmy_decorator(func:F)->F:@wraps(func)defwrapper(*args:Any,**kwargs:Any)->Any:returnfunc(*args,**kwargs)returnwrapper# type: ignore

三、实用装饰器模式

3.1 日志装饰器

基础版本

fromfunctoolsimportwrapsimportlogging logging.basicConfig(level=logging.INFO)logger=logging.getLogger(__name__)deflog_calls(func):@wraps(func)defwrapper(*args,**kwargs):logger.info(f"Calling{func.__name__}with args={args}, kwargs={kwargs}")try:result=func(*args,**kwargs)logger.info(f"{func.__name__}returned{result}")returnresultexceptExceptionase:logger.error(f"{func.__name__}raised{type(e).__name__}:{e}")raisereturnwrapper@log_callsdefadd(a:int,b:int)->int:returna+b add(1,2)# 输出:# INFO:__main__:Calling add with args=(1, 2), kwargs={}# INFO:__main__:add returned 3

高级版本:支持自定义日志级别和格式

fromfunctoolsimportwrapsfromtypingimportOptional,Callableimportloggingimporttimedeflog_calls(level:int=logging.INFO,message:Optional[str]=None,log_args:bool=True,log_result:bool=True,log_time:bool=False):"""高级日志装饰器 Args: level: 日志级别 message: 自定义消息模板 log_args: 是否记录参数 log_result: 是否记录返回值 log_time: 是否记录执行时间 """defdecorator(func:Callable)->Callable:@wraps(func)defwrapper(*args,**kwargs):logger=logging.getLogger(func.__module__)# 构建日志消息msg=messageorf"Calling{func.__name__}"iflog_args:msg+=f" with args={args}, kwargs={kwargs}"logger.log(level,msg)# 记录执行时间start_time=time.time()iflog_timeelseNonetry:result=func(*args,**kwargs)iflog_result:logger.log(level,f"{func.__name__}returned{result}")iflog_time:elapsed=time.time()-start_time logger.log(level,f"{func.__name__}took{elapsed:.4f}s")returnresultexceptExceptionase:logger.error(f"{func.__name__}raised{type(e).__name__
http://www.jsqmd.com/news/887350/

相关文章:

  • 凸优化理论导向的阵列天线方向图综合优化算法【附代码】
  • 基于边缘AI与LoRa的野外监测系统:从硬件设计到云端部署全解析
  • ssm电影网站(10097)
  • D3KeyHelper:暗黑3玩家的智能按键助手,告别重复操作疲劳
  • 基于MAX78000的离线语音控制RGB灯带:端侧AI全流程实践
  • Python自动连连看:计算机视觉如何实现游戏外挂的终极指南
  • 如何在5分钟内免费搭建你的第一个工业级虚拟PLC系统
  • 从社交关系到分子结构:图解GCN(图卷积网络)到底在‘看’什么?
  • 2026年5月正规的金山别墅平层大宅装修机构如何选厂家推荐榜,全案整装设计、全屋定制、别墅装修、旧房翻新厂家选择指南 - 海棠依旧大
  • 智能车竞赛实战:从传感器融合到控制算法的完整开发指南
  • 3步解锁音乐自由:ncmdump实现NCM转MP3的终极指南
  • 告别依赖地狱:用Anaconda虚拟环境一键搞定HiC-Pro 3.1.0安装(附细菌基因组实战配置)
  • 基于THAT1240芯片的平衡-非平衡音频转换器设计与实践
  • AI时代程序员职业发展与个人创业可行性研究报告
  • 2026年5月行业内江苏企业技术中心公司怎么选择厂家推荐榜,省级企业技术中心/国家级企业技术中心/市级企业技术中心认定辅导厂家选择指南 - 海棠依旧大
  • 告别纸上谈兵!用Multisim 14.0仿真这8类经典运放电路,实测波形与理论对比
  • 别再被论文里的‘95%置信度’吓到了!用Python模拟100次抽样,3分钟带你搞懂置信区间
  • 基于ESP32/ESP8266的本地化无线门铃通知系统设计与实现
  • c仿真ok,rtl仿真stall可能问题
  • 【前端开发者生存报告2024】:92%的重构返工源于忽略这3个Lovable前置指标
  • OpenCore Legacy Patcher完整方案:如何在老旧Mac上安装最新macOS的实用指南
  • RAG 实战指南:深入浅出向量数据库 Milvus
  • 2026年5月比较好的阳台防水补漏公司怎么选择厂家推荐榜,阳光房防水/采光井防水/窗台防水厂家选择指南 - 海棠依旧大
  • AI软件测试培训机构排行:淘宝电商设计培训、电商平台设计培训、电商设计线下培训、短剧视频剪辑培训、短视频剪辑培训选择指南 - 优质品牌商家
  • DIY USB-MIDI转五针DIN转换器:基于Arduino Pro Micro的硬件与软件实现
  • 基于ESP32打造高性价比网络收音机:硬件选型、软件配置与实战指南
  • DIY智能门铃:基于STM32与VS1053的无线音频播放系统设计
  • 宝藏合集!2026AI写作辅助网站大盘点(覆盖 99% 毕业论文需求)
  • 告别环境变量报错!保姆级图文详解:Windows 11下BurpSuite Pro 2024与JDK 17的完美安装配置
  • 实景三维重构赋能智慧仓储,黎阳之光打造仓库全域透明管控新生态