python中的装饰器的使用实战

1、了解装饰
装饰器的目的是在另一个函数中嵌入一个函数进行重复使用,不改变其结构,增加函数的使用方式,但不需要写太多冗余代码;
装饰本质上是Python函数,可以在不做任何代码变化的情况下增加其他函数的额外功能,装饰的返回值也是函数对象。
常用功能:1。引入日志;2.函数执行时间统计;3.执行函数前的准备;4.执行函数后的清理功能;5.权限验证;6.缓存
2、实现原理和一般写法
我们可以从一个简单的装饰器中推断出一个通用的装饰写作方法,简单地记录函数的运行时间
importtime
deftimer(func):
'''
记录装饰器的操作时间
:paramfunc:方法
:return:函数对象
'''
defdeco(*args,**kwargs):
startTime=time.time()
f=func(*args,**kwargs)
endTime=time.time()
msecs=(endTime-startTime)*1000
print("timeis%dms"%msecs)
returnf#如果func值得返回,则需要在此return返回。否则,默认返回值为none,一般默认返回
returndeco
@timer
deftest(parameter):
print("testisrunning!")
time.sleep(1)
return"Returnedvalue"#该函数具有返回值,因此需要在装饰器的deco方法中写入返回值
t=test('aa')
print(t)这是一种非常简单的装饰,可以记录时间,从而推导出一种通用的装饰写作方法:
deffunc_name(func):#装饰函数名称的自定义
defdeco(*args,**kwargs):#原封不动地传递所有参数
print("在此分割线上写下函数运行前的操作")
#-----------分割线-----------
f=func(*args,**kwargs)
#-----------分割线-----------
print("在这条分割线之后,return之前,编写函数运行后的操作")
returnf#如果func值得返回,则需要在此return返回。否则,默认返回值为none,一般默认返回
returndeco
@func_name
deftest(parameter):#8
print("testisrunning!")
time.sleep(1)
return"Returnedvalue"#该函数具有返回值,因此需要在装饰器的deco方法中写入返回值
t=test('aa')
print(t)ok 装饰可以在这里完成。一般来说,它可以满足需求。在互联网上阅读这么多原则是浪费时间。我更喜欢实用型。我真的不喜欢罗嗦那么多。我只是这么做。
当然,在开发过程中, 我们可能会遇到一些特殊情况,如参数问题
1、赋予装饰函数代参数(通用)
2、拆分计算执行函数的参数(如1000w的数据,拆分为100份执行等)(定制)
然后按顺序来
1、写代参数的装饰器
deflogging(level):
defwrapper(func):
definner_wrapper(*args,**kwargs):
print("[{level}]:enterfunction{func}()".format(level=level,func=func.__name__))
returnfunc(*args,**kwargs)
returninner_wrapper
returnwrapper
@logging(level='INFO')
defsay(something):
print("say{}!".format(something))
#假如没有使用@语法,就等于
#say=logging(level='INFO')(say)
@logging(level='DEBUG')
defdo(something):
print("do{}...".format(something))
if__name__='__main__':
say('hello')
do("mywork")发现:在上面的通用模板上又盖了一层!!,然后得到里面的参数! so easy!!!
2、写一个参数拆分的装饰器,稍微定制一下,不能像上面那样通用。举个例子 栗子:
deffunc_name(func):#装饰函数名称的自定义
defdeco(*args,**kwargs):#原封不动地传递所有参数
print(args[0])
f_list=[]
foriinrange(0,args[0],100000):
print(i)
f_list.append(func(i))
#f_list#这里应该按照既定的规则继续拼接这个结果。如果是写文件、入库等操作,不需要returnn
returnf_list#如果这里有返回值,应该是
returndeco
@func_name
deftest(parameter):#8
print("testisrunning!")
time.sleep(1)
return"Returnedvalue"#该函数具有返回值,因此需要在装饰器的deco方法中写入返回值
t=test(1000000)
print(t)可以看出,这种定制略高,不通用,但我们实现了我们的需求,所以我们应该理解和学习如何使用它!!!
可以看出,这种定制略高,不通用,但我们实现了我们的需求,所以我们应该理解和学习如何使用它!!!
下面介绍一下基于类实现的装饰器。问题来了。我是实战派,不需要类装饰器。所以,做个大盗,以后用了就不会瞎找了!!!
装饰函数实际上是一种接口约束。它必须接受一个callable对象作为参数,然后返回一个callable对象。在python中,callable对象通常是函数,但也有例外。只要对象重新加载__call__()方法,那么这个对象就是callable。
classTest(): def__call__(self): print'callme!' t=Test() t()#callme
像__call__这种前后划线的方法在Python中被称为内置方法,有时也被称为魔法方法。重载这些魔法方法通常会改变对象的内部行为。上面的例子使一个类对象有被调用的行为。
回到装饰器的概念,装饰器需要接受一个callable对象,并返回一个callable对象(不太严格,详见后面)。
所以也有可能通过类来实现。我们可以让类的构造函数__init__()接受函数,然后重载__call__()并返回一个函数,也可以达到装饰函数的效果。
classlogging(object):
def__init__(self,func):
self.func=func
def__call__(self,*args,**kwargs):
print"[DEBUG]:enterfunction{func}()".format(
func=self.func.__name__)
returnself.func(*args,**kwargs)
@logging
defsay(something):
print"say{}!".format(something)带参数的类装饰器
如果需要以类形式实现带参数的装饰,则会比前面的例子稍微复杂一些。那么,在构造函数中接受的不是函数,而是传入的参数。通过类保存这些参数。
然后重载___call__方法是接受函数并返回函数。
classlogging(object):
def__init__(self,level='INFO'):
self.level=level
def__call__(self,func):#接受函数
defwrapper(*args,**kwargs):
print"[{level}]:enterfunction{func}()".format(
level=self.level,
func=func.__name__)
func(*args,**kwargs)
returnwrapper#返回函数
@logging(level='INFO')
defsay(something):
print"say{}!".format(something) 