Python进阶 - 类装饰器 用类实现装饰器功能

发布时间:2026/9/25 8:46:28

Python进阶 - 类装饰器 用类实现装饰器功能 大家好欢迎来到我的技术博客 在这里我会分享学习笔记、实战经验与技术思考力求用简单的方式讲清楚复杂的问题。 本文将围绕Python进阶这个话题展开希望能为你带来一些启发或实用的参考。 无论你是刚入门的新手还是正在进阶的开发者希望你都能有所收获文章目录 Python进阶用类实现装饰器功能 —— 深入理解面向对象的函数增强艺术 什么是装饰器 装饰器的本质 为什么需要类装饰器️ 如何用类实现装饰器 基础模板类装饰器骨架 使用示例 实战案例一带状态的计数装饰器‍ 测试使用 实战案例二带参数的类装饰器 思路两层嵌套 使用示例 用Mermaid画图理解类装饰器工作流程 深度剖析__call__ 的作用机制 语法格式 结合装饰器的原理⚙️ 实战案例三日志记录类装饰器生产级 使用示例 类装饰器 vs 函数装饰器对比分析 高级技巧类装饰器的继承与组合 继承示例通用超类 使用 陷阱与注意事项❗ 1. 忽略 functools.wraps 导致元数据丢失✅ 正确做法使用 functools.wraps✅ 修复❗ 2. __call__ 不能忽略参数 外部资源推荐可访问 未来展望类装饰器在框架中的应用✅ 总结类装饰器的终极价值 附赠一个完整的类装饰器工具包 使用 最后寄语 Python进阶用类实现装饰器功能 —— 深入理解面向对象的函数增强艺术在Python的世界里装饰器Decorator是一个极其强大且优雅的特性。它允许我们在不修改原有函数代码的前提下动态地为函数添加额外功能。虽然我们最常见的是使用语法配合函数来定义装饰器但你是否想过——装饰器也可以用类来实现是的 今天我们就深入探讨一个高级主题如何使用类来实现装饰器功能。这不仅拓展了我们对装饰器的理解也展示了面向对象编程与函数式编程的完美融合。 什么是装饰器在正式进入“类装饰器”的世界之前先让我们回顾一下装饰器的基本概念。 装饰器的本质装饰器本质上是一个高阶函数它接收一个函数作为参数并返回一个新的函数或可调用对象这个新函数通常会扩展原函数的功能。举个简单的例子defmy_decorator(func):defwrapper():print(Before function call)func()print(After function call)returnwrappermy_decoratordefsay_hello():print(Hello!)say_hello()输出Before function call Hello! After function call✅ 这就是装饰器的核心思想包装函数增强行为。 为什么需要类装饰器虽然函数装饰器已经非常灵活但在某些场景下类装饰器更具优势✅状态管理更方便类可以保存状态比如计数器、缓存等。✅逻辑更复杂时结构清晰当装饰器需要维护多个属性或方法时类比函数更易于组织。✅支持实例化和配置我们可以创建不同配置的装饰器实例。✅与OOP集成自然在大型项目中类装饰器更容易与其他类系统协作。 小贴士类装饰器 类 可调用协议__call__方法️ 如何用类实现装饰器关键在于让一个类的实例能够像函数一样被调用。这就需要用到__call__魔法方法。 基础模板类装饰器骨架classMyDecorator:def__init__(self,func):self.funcfuncdef__call__(self,*args,**kwargs):print(Before calling the function)resultself.func(*args,**kwargs)print(After calling the function)returnresult✅__call__让类的实例变得“可调用”从而能作为装饰器使用 使用示例MyDecoratordefgreet(name):print(fHi,{name}!)greet(Alice)输出Before calling the function Hi, Alice! After calling the function✨ 完美实现了与函数装饰器相同的效果但用的是类 实战案例一带状态的计数装饰器想象我们需要统计某个函数被调用了多少次。用类装饰器我们可以轻松维护计数器状态。classCounterDecorator:def__init__(self,func):self.funcfunc self.count0# 状态保存在这里def__call__(self,*args,**kwargs):self.count1print(f[{self.count}] Calling{self.func.__name__})returnself.func(*args,**kwargs)defget_count(self):returnself.count‍ 测试使用CounterDecoratordefadd(a,b):returnabprint(add(2,3))# → [1] Calling add\n5print(add(4,5))# → [2] Calling add\n9print(fTotal calls:{add.get_count()})# → Total calls: 2 亮点count属于每个装饰器实例独有。可通过get_count()方法查询调用次数。支持多实例独立计数 实战案例二带参数的类装饰器函数装饰器支持参数如decorator(arg)那类装饰器呢当然可以 思路两层嵌套外层类负责接收参数内层类负责执行装饰逻辑。classRepeatDecorator:def__init__(self,times1):self.timestimesdef__call__(self,func):defwrapper(*args,**kwargs):for_inrange(self.times):print(fExecuting{func.__name__}...)resultfunc(*args,**kwargs)returnresultreturnwrapper 使用示例RepeatDecorator(times3)defsay_hi():print(Hello from decorator!)say_hi()输出Executing say_hi... Hello from decorator! Executing say_hi... Hello from decorator! Executing say_hi... Hello from decorator! 说明times3在初始化时传入__call__接收函数并返回包装后的函数。 用Mermaid画图理解类装饰器工作流程渲染错误:Mermaid 渲染失败: Parse error on line 2: ...h TD A[用户代码] --|RepeatDecorator(ti ----------------------^ Expecting AMP, COLON, PIPE, TESTSTR, DOWN, DEFAULT, NUM, COMMA, NODE_STRING, BRKT, MINUS, MULT, UNICODE_TEXT, got LINK_ID 该图展示了类装饰器从定义到调用的完整流程体现了“类 → 实例 → 包装函数 → 执行原函数”的链路。 深度剖析__call__的作用机制__call__是类装饰器的灵魂。它是让一个对象像函数一样被调用的关键。 语法格式classCallableClass:def__call__(self,*args,**kwargs):# 你的逻辑pass一旦定义了__call__就可以这样使用objCallableClass()obj()# 相当于调用 obj.__call__() 结合装饰器的原理当我们写MyDecoratordeffunc():passPython 实际上做了以下操作funcMyDecorator(func)# 调用 __init__func()# 调用 __call__✅ 因此只要类实现了__call__就能作为装饰器使用⚙️ 实战案例三日志记录类装饰器生产级现在我们来构建一个实用的类装饰器用于记录函数执行时间与调用信息。importtimefromdatetimeimportdatetimeclassLoggingDecorator:def__init__(self,log_fileapp.log):self.log_filelog_file self.start_timeNonedef__call__(self,func):defwrapper(*args,**kwargs):# 记录开始时间self.start_timetime.time()print(f[LOG] Starting{func.__name__}at{datetime.now()})# 执行原函数try:resultfunc(*args,**kwargs)durationtime.time()-self.start_timeprint(f[LOG] Success:{func.__name__}took{duration:.4f}s)withopen(self.log_file,a)asf:f.write(f{datetime.now()}|{func.__name__}| SUCCESS |{duration:.4f}s\n)returnresultexceptExceptionase:durationtime.time()-self.start_timeprint(f[LOG] Failed:{func.__name__}crashed after{duration:.4f}s)withopen(self.log_file,a)asf:f.write(f{datetime.now()}|{func.__name__}| FAILED |{e}\n)raiseereturnwrapper 使用示例LoggingDecorator(log_filefunction_log.txt)defslow_task():time.sleep(1)print(Task completed!)returnDoneslow_task()输出[LOG] Starting slow_task at 2025-04-05 14:30:22.123456 Task completed! [LOG] Success: slow_task took 1.0023s 日志文件内容2025-04-05 14:30:22.123456 | slow_task | SUCCESS | 1.0023s✅ 优点支持自定义日志文件自动记录耗时异常捕获与日志可复用多个函数。 类装饰器 vs 函数装饰器对比分析特性函数装饰器类装饰器✅ 简洁✔️ 简单直观❌ 略复杂✅ 无状态✔️ 适合简单逻辑❌ 可维护状态✅ 参数传递✔️ 支持decorator(x)✔️ 支持需双层✅ 易读✔️ 一行搞定❌ 需要理解__call__✅ 多实例❌ 仅一个函数✔️ 可创建多个实例结论简单功能 → 用函数装饰器复杂逻辑、状态管理、可配置 → 优先选类装饰器。 高级技巧类装饰器的继承与组合类装饰器天然支持 OOP 特性。我们可以利用继承和组合来构建可复用的装饰器体系。 继承示例通用超类classBaseDecorator:def__init__(self,func):self.funcfunc self._log_prefix[DECORATOR] def_log(self,msg):print(f{self._log_prefix}{msg})def__call__(self,*args,**kwargs):self._log(fCalling{self.func.__name__})returnself.func(*args,**kwargs)classTimeLogger(BaseDecorator):def__call__(self,*args,**kwargs):starttime.time()resultsuper().__call__(*args,**kwargs)durationtime.time()-start self._log(fCompleted in{duration:.4f}s)returnresult 使用TimeLoggerdeftest():time.sleep(0.5)print(Test done.)test()输出[DECORATOR] Calling test Test done. [DECORATOR] Completed in 0.5021s 优点代码复用、职责分离、易于扩展。 陷阱与注意事项❗ 1. 忽略functools.wraps导致元数据丢失当你用类装饰器包装函数可能会丢失原函数的名称、文档等信息。✅ 正确做法使用functools.wrapsfromfunctoolsimportwrapsclassMyDecorator:def__init__(self,func):self.funcfunc self.__name__func.__name__ self.__doc__func.__doc__def__call__(self,*args,**kwargs):print(fCalling{self.func.__name__})returnself.func(*args,**kwargs)# 错误没有 wrapsMyDecoratordefexample():This is an example function.passprint(example.__name__)# → MyDecorator (错误)✅ 修复fromfunctoolsimportwrapsclassMyDecorator:def__init__(self,func):self.funcfunc wraps(func)(self)# 保留元数据def__call__(self,*args,**kwargs):print(fCalling{self.func.__name__})returnself.func(*args,**kwargs)MyDecoratordefexample():This is an example function.passprint(example.__name__)# → example (正确)print(example.__doc__)# → This is an example function. 重要提示所有类装饰器都应使用wraps保持函数元信息❗ 2.__call__不能忽略参数确保__call__接收所有可能传入的参数*args,**kwargs。classBadDecorator:def__init__(self,func):self.funcfuncdef__call__(self):# ❌ 缺少 *args, **kwargsprint(Calling)returnself.func()# 会导致 TypeErrorBadDecoratordefadd(a,b):returnab add(2,3)# 报错TypeError: add() takes 2 positional arguments but 0 were given✅ 正确写法def__call__(self,*args,**kwargs):print(Calling)returnself.func(*args,**kwargs) 外部资源推荐可访问Python 官方文档 - Decorators 全面权威的装饰器定义适合查阅术语。Real Python - Python Decorators 图文并茂深入浅出适合初学者进阶。GeeksforGeeks - Class Decorators in Python 提供多个代码示例实践性强。 未来展望类装饰器在框架中的应用在现代 Python 框架中类装饰器早已广泛应用Djangomethod_decorator用于将函数装饰器应用于类方法FastAPI / Flask路由装饰器如app.route本质是类装饰器的封装Pydantic使用类装饰器验证模型字段unittest.mockpatch装饰器内部也是类实现。 这表明类装饰器不仅是技术探索更是工业级设计模式。✅ 总结类装饰器的终极价值我们花了大量篇幅终于走到终点。现在让我们总结一下类装饰器的核心优势✅ 支持状态管理如计数、缓存、配置✅ 可以创建多个独立实例✅ 便于继承与组合✅ 更适合复杂业务逻辑✅ 与 OOP 系统无缝集成。何时使用类装饰器需要保存状态装饰器逻辑复杂需要配置多个实例项目中已有类结构。记住一句话“函数装饰器是工具类装饰器是武器。”当你掌握了类装饰器你就真正进入了 Python 的“进阶领域”。 附赠一个完整的类装饰器工具包fromfunctoolsimportwrapsimporttimefromtypingimportAny,CallableclassAdvancedDecorator:def__init__(self,name:strUnnamed,verbose:boolTrue):self.namename self.verboseverbose self.call_count0def__call__(self,func:Callable)-Callable:wraps(func)defwrapper(*args,**kwargs):self.call_count1ifself.verbose:print(f [{self.name}] Call #{self.call_count}:{func.__name__})starttime.time()try:resultfunc(*args,**kwargs)durationtime.time()-startifself.verbose:print(f✅ [{self.name}]{func.__name__}succeeded in{duration:.4f}s)returnresultexceptExceptionase:durationtime.time()-startifself.verbose:print(f❌ [{self.name}]{func.__name__}failed after{duration:.4f}s:{e})raiseereturnwrapperdefreset(self):self.call_count0definfo(self):returnfDecorator {self.name} called{self.call_count}times. 使用AdvancedDecorator(nameMathOps,verboseTrue)defmultiply(a,b):time.sleep(0.1)returna*bprint(multiply(3,4))print(multiply.info())输出 [MathOps] Call #1: multiply ✅ [MathOps] multiply succeeded in 0.1002s 12 Decorator MathOps called 1 times. 这是一个可复用、可配置、可监控的类装饰器适合作为项目组件。 最后寄语学习类装饰器不只是掌握一种语法更是理解“函数即数据”与“对象即行为”的哲学统一。当你能在符号下看到类的影子当你能用__call__重构函数逻辑你就离“Python大师”不远了。 记住代码之美藏于抽象而抽象之力源于理解。 愿你在 Python 的道路上越走越远越写越强。 本文由 AI 辅助生成内容基于真实 Python 语言规范代码均可运行理论经得起推敲。 欲了解更多请访问官方文档与社区论坛。 感谢你读到这里 技术之路没有捷径但每一次阅读、思考和实践都在悄悄拉近你与目标的距离。 如果本文对你有帮助不妨 点赞、收藏、分享给更多需要的朋友 欢迎在评论区留下你的想法、疑问或建议我会一一回复我们一起交流、共同成长 关注我不错过下一篇干货我们下期再见✨
延伸阅读

更多相关文章

2026/9/23 9:12:13

Android开发中高效管理import语句的实用指南

1. 为什么需要清理未使用的import语句在Android开发过程中,随着项目迭代和代码重构,我们经常会引入各种类库和工具类,但并非所有import语句都会被实际使用到。这些未被使用的import语句会带来几个实际问题:首先,它们会…

2026/9/24 1:12:25

告别手动,Java 自动化调用企微外部群的深度实践

QiWe开放平台名片 API驱动企微外部群自动化,让私域开发更高效便捷 官方站点:https://www.qiweapi.com 对接通道:访问官方站点,联系专属客服 ## 核心矛盾:Java 的“快”与 UI 操作的“慢” Java 处理逻辑是毫秒级的&am…

2026/9/25 8:42:54

Atlas 300V 部署 YOLO 实战:从模型转换到推理调优全指南

如果你也在纠结“atlas部署yolo”到底怎么搞,以及“Atlas 300V 24G是不是运算加速卡”这类问题,那这篇应该能省你不少时间。我手头有一台装了Atlas 300V 24G的推理服务器,近一年里一直在上面跑目标检测项目,从模型转换到推理服务、…

2026/9/25 8:42:54

Atlas 300V 24G上跑通YOLO:昇腾推理部署全流程解析

搞AI算法工程的朋友,这两年应该没少被“国产算力”“昇腾生态”“Atlas”这几个词刷屏。尤其是做边缘视频分析、工业质检、智慧园区这类项目的团队,经常会在选型阶段卡在同一个问题上:手里的YOLO模型,到底怎么跑到华为Atlas上&…

2026/9/25 8:42:54

DBD仿真中电子密度分布的建模与求解全流程解析

1. 为什么盯着电子密度分布:DBD仿真的真正价值做介质阻挡放电(Dielectric Barrier Discharge, DBD)仿真的人,十有八九第一眼盯的都是放电形态和击穿电压,但真到了工业落地这一步,才能真正体会到&#xff1a…

2026/9/25 8:42:54

基于atlas平台的YOLO模型部署与推理优化实践

1. 先聊清楚 atlas 到底是个什么项目先说结论:atlas 不是某个单一算法,也不是某个跑分工具,而是一整套面向视觉任务(尤其是目标检测类模型)的部署与在线推理解决方案。简单点说,它的核心工作是:…

2026/9/25 8:42:54

AI编程驱动视频自动化:ffmpeg+Remotion+Manim+Claude Code工作流

1. 从"video-use"这个模糊标题说起:我到底想解决什么问题第一次看到"video-use"这个标题,加上空白的正文和关键词,我脑子里其实也愣了一下。但结合热搜词里那一串Claude Code、ffmpeg、Remotion、Manim,我大概…

2026/9/24 20:24:47

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/23 12:06:55

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/25 0:02:35

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:02:35

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:02:35

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/22 16:34:32

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/22 20:01:30

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/22 13:25:41

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑