本文转载自微信公众号“东方儿”,作者东方儿。转载本文请联系东方儿公众号。函数装饰器是Python语言最好的设计之一。它以非常简洁的方式增强了功能的行为,使崎岖不平的道路变得平坦。什么是函数装饰器?函数装饰器是一个可调用对象,其参数是另一个函数。例如:@decorateddeftarget():print("runningtarget()")与以下代码具有相同的效果:func):definner():print("runninginner()")returninner测试一下:>>>target()runninginner()>>>target.innerat0x04899D18>新目标是decorate返回的inner(目标)功能。因为装饰器只是一种代码优化手段,不像for语句那样决定程序流程,严格来说,装饰器只是语法糖。它有两个特点,一是可以用其他函数替换被装饰的函数,二是装饰器在模块加载时立即执行。装饰器在导入时执行。要真正理解装饰器,您需要区分导入时间和运行时间。函数装饰器在导入模块时立即执行,而装饰函数仅在显式调用时运行。下面通过例子来解释这个特性,新建一个registration.py模块:registry=[]defregister(func):#装饰器函数也可以不定义内部函数print("runningregister(%s)"%func)registry.append(func)returnfunc@registerdeff1():print("runningf1()")@registerdeff2():print("runningf2()")deff3():print("runningf3()")defmain():print("runningmain()")print("registry->",registry)f1()f2()f3()if__name__=="__main__":main()从结果可以看出@register的行为在f1和f2上,并被导入,它在调用main()之前执行。f3没有装饰器,所以在调用main()之前不会执行@register。调用main()后,仅在显式调用f1()、f2()和f3()后才执行该函数。导入模块可以看得更清楚:>>>importregistrationrunningregister()runningregister()装饰器在导入时执行。使用装饰器改进策略模式在?文章中提到装饰器可以更优雅地实现策略模式的最优策略。其实现代码如下:promos=[]defpromotion(promo_func):promos.append(promo_func)returnpromo_func@promotiondeffidelity(order):"""5%discountforcustomerswith1000ormorefidelitypoints"""returnorder.total()*.05iforder.customer.fidelity>=1000else0@promotiondefbulk_item(order):"""10%discountforeachLineItemwith20ormoreunits"""minorder.fidelity=0forartite:ifitem.quantity>=20:discount+=item.total()*.1returndiscount@promotiondeflarge_order(order):"""7%discountfororderswith10ormoredistinctitems"""distinct_items={item.productforiteminorder.cart}iflen(distinct_items)>=10:returnorder.total()*.07return0defbest_promo(order):"""Selectbestdiscountavailable"""returnmax(promo(order)forpromoinpromos)它解决了“如果要添加新的促销策略,则定义相应的函数并将其添加到促销列表中”这个缺陷,并且具有更多优点:可以使用@promotion装饰器添加新的促销策略。促销策略函数不需要以_promo结尾,可以任意排序。可以在任何模块中定义促销策略,只需使用@promotion装饰器即可。总结本文首先介绍函数装饰器是一个可调用对象,它的参数是另一个函数。严格来说,它只是语法糖。要理解装饰器,需要区分导入时间和运行时,装饰器是在导入时执行的。最后,使用装饰器优化策略模式的最佳策略。为了进一步研究函数装饰器,你必须首先了解另一个非常重要的概念:闭包。参考资料:《流畅的Python》