Python装饰器入门学习教程(九步学习)
装饰器(decorator)是一种高级Python语法。装饰器可以对一个函数、方法或者类进行加工。在Python中,我们有多种方法对函数和类进行加工,比如在Python闭包中,我们见到函数对象作为某一个函数的返回结果。相对于其它方式,装饰器语法简单,代码可读性高。因此,装饰器在Python项目中有广泛的应用。
这是在Python学习小组上介绍的内容,现学现卖、多练习是好的学习方式。
第一步:最简单的函数,准备附加额外功能
#-*-coding:gbk-*- '''示例1:最简单的函数,表示调用了两次''' defmyfunc(): print("myfunc()called.") myfunc() myfunc()
第二步:使用装饰函数在函数执行前和执行后分别附加额外功能
#-*-coding:gbk-*- '''示例2:替换函数(装饰) 装饰函数的参数是被装饰的函数对象,返回原函数对象 装饰的实质语句:myfunc=deco(myfunc)''' defdeco(func): print("beforemyfunc()called.") func() print("aftermyfunc()called.") returnfunc defmyfunc(): print("myfunc()called.") myfunc=deco(myfunc) myfunc() myfunc()
第三步:使用语法糖@来装饰函数
#-*-coding:gbk-*- '''示例3:使用语法糖@来装饰函数,相当于“myfunc=deco(myfunc)” 但发现新函数只在第一次被调用,且原函数多调用了一次''' defdeco(func): print("beforemyfunc()called.") func() print("aftermyfunc()called.") returnfunc @deco defmyfunc(): print("myfunc()called.") myfunc() myfunc()
第四步:使用内嵌包装函数来确保每次新函数都被调用
#-*-coding:gbk-*- '''示例4:使用内嵌包装函数来确保每次新函数都被调用, 内嵌包装函数的形参和返回值与原函数相同,装饰函数返回内嵌包装函数对象''' defdeco(func): def_deco(): print("beforemyfunc()called.") func() print("aftermyfunc()called.") #不需要返回func,实际上应返回原函数的返回值 return_deco @deco defmyfunc(): print("myfunc()called.") return'ok' myfunc() myfunc()
第五步:对带参数的函数进行装饰
#-*-coding:gbk-*- '''示例5:对带参数的函数进行装饰, 内嵌包装函数的形参和返回值与原函数相同,装饰函数返回内嵌包装函数对象''' defdeco(func): def_deco(a,b): print("beforemyfunc()called.") ret=func(a,b) print("aftermyfunc()called.result:%s"%ret) returnret return_deco @deco defmyfunc(a,b): print("myfunc(%s,%s)called."%(a,b)) returna+b myfunc(1,2) myfunc(3,4)
第六步:对参数量不确定的函数进行装饰
#-*-coding:gbk-*- '''示例6:对参数数量不确定的函数进行装饰, 参数用(*args,**kwargs),自动适应变参和命名参数''' defdeco(func): def_deco(*args,**kwargs): print("before%scalled."%func.__name__) ret=func(*args,**kwargs) print("after%scalled.result:%s"%(func.__name__,ret)) returnret return_deco @deco defmyfunc(a,b): print("myfunc(%s,%s)called."%(a,b)) returna+b @deco defmyfunc2(a,b,c): print("myfunc2(%s,%s,%s)called."%(a,b,c)) returna+b+c myfunc(1,2) myfunc(3,4) myfunc2(1,2,3) myfunc2(3,4,5)
第七步:让装饰器带参数
#-*-coding:gbk-*- '''示例7:在示例4的基础上,让装饰器带参数, 和上一示例相比在外层多了一层包装。 装饰函数名实际上应更有意义些''' defdeco(arg): def_deco(func): def__deco(): print("before%scalled[%s]."%(func.__name__,arg)) func() print("after%scalled[%s]."%(func.__name__,arg)) return__deco return_deco @deco("mymodule") defmyfunc(): print("myfunc()called.") @deco("module2") defmyfunc2(): print("myfunc2()called.") myfunc() myfunc2()
第八步:让装饰器带类参数
#-*-coding:gbk-*- '''示例8:装饰器带类参数''' classlocker: def__init__(self): print("locker.__init__()shouldbenotcalled.") @staticmethod defacquire(): print("locker.acquire()called.(这是静态方法)") @staticmethod defrelease(): print("locker.release()called.(不需要对象实例)") defdeco(cls): '''cls必须实现acquire和release静态方法''' def_deco(func): def__deco(): print("before%scalled[%s]."%(func.__name__,cls)) cls.acquire() try: returnfunc() finally: cls.release() return__deco return_deco @deco(locker) defmyfunc(): print("myfunc()called.") myfunc() myfunc()
第九步:装饰器带类参数,并分拆公共类到其他py文件中,同时演示了对一个函数应用多个装饰器
#-*-coding:gbk-*- '''mylocker.py:公共类for示例9.py''' classmylocker: def__init__(self): print("mylocker.__init__()called.") @staticmethod defacquire(): print("mylocker.acquire()called.") @staticmethod defunlock(): print("mylocker.unlock()called.") classlockerex(mylocker): @staticmethod defacquire(): print("lockerex.acquire()called.") @staticmethod defunlock(): print("lockerex.unlock()called.") deflockhelper(cls): '''cls必须实现acquire和release静态方法''' def_deco(func): def__deco(*args,**kwargs): print("before%scalled."%func.__name__) cls.acquire() try: returnfunc(*args,**kwargs) finally: cls.unlock() return__deco return_deco #-*-coding:gbk-*-
'''示例9:装饰器带类参数,并分拆公共类到其他py文件中
同时演示了对一个函数应用多个装饰器'''
frommylockerimport* classexample: @lockhelper(mylocker) defmyfunc(self): print("myfunc()called.") @lockhelper(mylocker) @lockhelper(lockerex) defmyfunc2(self,a,b): print("myfunc2()called.") returna+b if__name__=="__main__": a=example() a.myfunc() print(a.myfunc()) print(a.myfunc2(1,2)) print(a.myfunc2(3,4))
以上给大家分享了Python装饰器入门学习教程(九步学习),希望对大家有所帮助。