当前位置: 首页 > 科技观察

拿到三大神器的Python装饰器

时间:2023-03-16 19:21:14 科技观察

装饰器,几乎在各大Python框架中都能看到它的身影,足以见其价值!它具有动态改变函数或类函数的魔力!1.什么是装饰对于f等被封装的原始函数,装饰器可以在f函数执行之前或之后运行一些代码。2.装饰器的结构装饰器也是一个函数,它装饰了原函数f或者类cls,然后返回一个函数g来装饰一个函数:defdecorator(f):#define要返回的函数defg():print('functionActionsbeforeexecutionoffun')f()print('Actionsafterexecutionoffunctionf')return装饰类:defdecorator(cls):#定义要返回的函数defg():print('类cls执行前的动作')f()print('类cls执行后的动作')return使用装饰器很简单,@+customdecorator对要装饰的函数进行装饰。3.为什么要这样做要理解装饰器为什么会有这样的结构,首先要明白装饰器的目标是什么。它的价值在于在原函数f的基础上增加了一些行为。前提一定不能破坏函数f,所以f的内部结构一定不能改变,所以有些行为只能在调用f前后定义。同时,装饰器函数decorator的返回值是多少?大家可以考虑一下,还不如返回一个函数,把原来的函数f.4包装起来。装饰一个函数。printStar函数接收一个函数f,返回值也是一个函数,所以符合装饰器的结构要求,所以printStar是一个装饰器。defprintStar(f):defg():print('*'*20)f()print('*'*20)returngprintStar装饰器实现函数f执行前后打印20个*字符。使用printStar:@printStardeff():print('helloworld')call:if__name__=='__main__':###改变函数functionf()printresult:************************helloworld*********************可以很方便的装饰其他想装饰的函数,如下:@printStardefg():print('welcometoPython')5。装饰一个类,除了装饰函数f,还可以装饰类cls。两者的原理是一样的。下面是一个装饰器实现单例模式的例子。所谓单例,就是类只有一个实例,不能有第二个。defsingleton(cls):instance={}defget_instance(*args,**kwargs):ifclsnotininstance:instance[cls]=cls(*args,**kwargs)returninstance[cls]returnget_instance定义字典实例,key-value对是类和实例,这确保只有cls()一次。使用装饰器单例修改类:@singletonclassCorePoint:passtest:if__name__=='__main__':###改变类的功能c1=CorePoint()c2=CorePoint()print(c1isc2)#True6.装饰器堆叠在原函数上f不仅可以被一个装饰器装饰,也可以被n多个装饰器装饰。接下来,定义一个装饰器printLine,它在装饰函数执行前后打印20:defprintLine(f):defg():print('-'*20)f()print('-'*20)returnuses上面定义好的printStar和printLine同时修饰了函数f:@printStar@printLinedeff():print('helloworld')此时调用函数f:if__name__=='__main__':###Changethefunction函数f()打印结果:********************--------------------helloworld----------------------********************f修饰后,先打印*,再打印-再级联一层,原来的函数f就变强了。使用装饰器还可以实现功能分离,进一步实现松散耦合。7、温馨提示打印原函数f的名称__name__,结果为fIn[1]:deff():...:passIn[4]:f.__name__Out[4]:'f'但是,函数名被f装饰后变成了g,这不是我们想要的!@printStardeff():passf()f.__name__#gPython提供了解决方案:使用functools模块中的wraps装饰器:fromfunctoolsimportwrapsdefprintStar(f):@wraps(f)defg():print('*'*20)f()print('*'*20)此时返回,打印修饰后f的名称,并显示f,正常!