decorator

张开发
2026/5/15 20:17:23 15 分钟阅读
decorator
装饰器这东西乍一听可能觉得挺玄乎好像是什么高级魔法。其实说白了它就是一种包装。咱们平时收快递包裹外面那层纸箱或者塑料袋就是个装饰器。里面的东西没变但多了层保护或者多了张快递单功能上多了一点。在 Python 里函数就是那个“里面的东西”。有时候你想给这个函数加点料比如记录一下它什么时候被调用的或者看看它运行了多久又或者检查一下参数对不对。最直接的办法就是打开这个函数在它的代码里加上几行记录时间的代码。但这么做有点笨一来破坏了原来的函数二来如果十个函数都要加你就得改十次。这时候装饰器的想法就来了。不如我们做个“盒子”把函数放进去。这个盒子本身也是个函数它接收你的原函数然后在内部定义一个新的函数。在这个新函数里你可以先做点额外操作比如记录开始时间然后调用原来的函数拿到结果再做点收尾操作比如记录结束时间并计算耗时最后把结果返回出去。从外面看你调用的还是那个函数名但它已经具备了新的行为。举个例子假设你有个函数专门用来打招呼。defsay_hello(name):returnfHello,{name}!现在想看看执行这个函数要花多久。你可以写一个计时的装饰器。importtimedeftimer(func):defwrapper(*args,**kwargs):starttime.time()resultfunc(*args,**kwargs)endtime.time()print(f{func.__name__}took{end-start:.2f}seconds to run.)returnresultreturnwrapper怎么用呢最直观的用法是这样say_hellotimer(say_hello)print(say_hello(World))运行后除了打印问候语还会看到一行时间记录。这里timer就是那个装饰器函数它吃进去一个say_hello吐出来一个新的函数wrapper。我们把这个新函数重新赋值给say_hello这个名字。以后调用say_hello实际上调用的是被包装过的wrapper。Python 觉得这种写法还不够方便于是提供了这个语法糖。你可以在函数定义前直接加上timer。timerdefsay_hello(name):returnfHello,{name}!效果和上面那种手动赋值一模一样但看起来清爽多了。这个符号就像是在给函数贴上一个标签告诉 Python“喂在用它之前先给它套上这个盒子。”装饰器真正厉害的地方在于它的可组合性。你可以给一个函数套上多个盒子。比如你既想计时又想记录日志。那就写两个装饰器然后叠着用。logtimerdefsome_function():...这时候some_function会先被timer包装然后再被log包装。顺序就像穿衣服是从下往上的离函数定义最近的先执行。说到这里你可能觉得装饰器就是用来增强函数的。这没错但它的本质其实是“函数变换”。它输入一个函数对象输出一个新的函数对象。这种对函数本身进行操作和变换的能力是函数作为“一等公民”特性的直接体现。在 Python 里函数可以像整数、字符串一样被传递、修改和返回装饰器是这种理念最优雅的应用之一。除了用在函数上装饰器也能用在类上或者类的方法上。类装饰器相对少见一些但原理相通只不过它操作的是类这个对象。刚开始接触时可能会被那个嵌套的def wrapper搞糊涂。多写几次多调试几次看看执行流程就明白了。关键点在于装饰器函数如timer只在函数定义时执行一次它返回的wrapper函数才是每次调用时真正执行的东西。还有一个常遇到的坑是关于函数身份的。被装饰后函数的__name__等元信息会变成wrapper的这有时会破坏一些依赖元信息的工具。解决方法是使用functools.wraps这个装饰器把它加在你写的wrapper函数上它能帮你把原函数的元信息复制过来。fromfunctoolsimportwrapsdeftimer(func):wraps(func)defwrapper(*args,**kwargs):...returnwrapper这本身也是个很有趣的现象我们用装饰器来修复另一个装饰器带来的副作用。在实际项目中装饰器无处不在。Web框架里用它来定义路由app.route(/)用它来做权限检查测试框架里用它来标记测试用例大型应用中用它来实现插件机制或中间件。它把那些横切在各个函数之间的通用逻辑比如日志、鉴权、事务管理干净地剥离了出来让核心业务代码保持简洁。理解装饰器算是从“写脚本”到“做工程”的一个小台阶。它背后体现的是一种不直接修改原有对象而是通过包装和组合来扩展功能的设计思想。这种思想在很多优秀的软件设计中都能看到影子。下次再看到那个符号或许可以想想它不仅仅是一个语法工具更是通往更灵活代码组织方式的一扇小门。

更多文章