什么是装饰器?
- 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码修改的提前增加额外功能。
- 装饰器的返回值也是一个函数对象。
- 装饰器的作用就是为已经存在的对象添加额外的功能。
#原函数 improt time def foo (): #原函数 print ("guo hailan") time.sleep(2) def bar():#原函数 print ("tang qinghua") time.sleep(3)
#需求,在原函数新增一个计时的功能
实例:
def foo(): start = time.time()#获取当前时间 print ("guo hailan") time.sleep(2) end = time.time() print ("spend %s"%(end - start))#计算执行用了多长时间 def bar(): start = time.time()()#获取当前时间 print ("tang qinghua") time.sleep(3) end = time.time() print ("spend %s"%(end - start) """ 函数虽然实现了功能,但是改变了原来的功能函数,如果是公共函数,修改一旦出错,影响到整个各个功能都出错。
不允许你动我的原函数,这是封闭原则,还有一个开放原则,虽然你不可以在原功能上修改,但是你可以扩展 """
新增功能,重复代码太多
这样就造成大量雷同的代码,为了减少重复写代码,我们可以这样做,重新定义一个函数,定义一个专门显示时间的函数
实例:
def show_time(): start = time.time() foo()#需要计时的函数 end = time.time() print ("spend %s"%(end - start))
"""
这个函数只能计算foo()函数的时间
如果要计算bar时间怎么办,又要重建立新的函数呢
"""
#我们将定义显示时间函数,传一个参数(传入功能函数)计算哪个函数就传入哪个函数名字。
实例:
def show_time(f): #f是传入的参数函数 start = time.time() f() #接受的函数 end = time.time() print ("spend %s"%(end - start)) show_time(foo)#调用函数 show_time(bar) """ 功能是实现了,但是调用方式改变了,之前调用的是foo(), 所有调用foo()的函数都要跟着改成show_time() 所有的业务都要跟着改,有点不合理 """
问题是怎么不改变调用方式能实现功能。我们的要求是,调用foo()就能实现原函数功能和计时功能。
我们可以对show_time(foo)赋值,做一个嵌套函数
def show_time(f): #装饰器函数,(这个函数要放在最前面,因为后面调用的时候需要先存到内存里面) def inner(): start = time.time() f() end = time.time() print ("spend %s"%(end - start)) return inner #装饰函数返回值是一个函数对象(返回的是inner的内在地址) foo = show_time(foo) #赋值给foo (这一句要放在原有函数的下面) def foo(): print ("guo hailan") time.sleep() foo = show time(foo) foo()#执行这个的时候相当于是执行inner函数 '''
python 提供了一个比较高大上的表示方法@show_time @show_time等价于 foo = show time(foo) @show_time 放在原功能函数的上面 ''' 实例: @show_time() def foo(): print ("guo hailan") time.sleep(3) foo() #函数调用
功能函数加参数
实例:
#功能函数加参数 def show_time(f): def inner(x,y): start = time.time() f(x,y) end = time.time() print ("spend %s"%(end - start)) return inner @show_time() # 等价 add = show_time(add) def add(a,b): print (a+b) time.sleep(3) add(2,2)
功能函数传不定长参数
实例:
#功能函数传不定长参数 def show_time(f): def inner(*x,**y): start = time.time() f(*x,**y) end = time.time() print ("spend %s"%(end - start)) return inner
@show_time() # 等价 add = show_time(add) def add(*a,**b): #功能函数 sums = 0 for i in range(a) sums + = i #等价 sums = sums + i print (sums) time.sleep(3) add(1,3,5,7,9) #这一串传进去给*a
装饰器加参数
#装饰器加参数 def logger(flag="")#加上这个是因为要向外界要个参数进来,默认为空,传true才会打印日志 def show_time(f): def inner(*x,**y): start = time.time() f(*x,**y) end = time.time() print ("spend %s"%(end - start)) if flag == "true": #必须传true的时候才会打印日志记录 print "打印日志记录" else: pass return inner return show_time ---------------------------------------------- @logger("true")#调用bar的时候需要打印日志,传入参数 def bar(): #功能函数 print ("bar....") time.sleep(3) bar() ------------------------------------------- @logger("eee")#随便传入一个不会打印日志,设置了传true才打印 def bar(): #功能函数 print ("bar....") time.sleep(3) bar() --------------------------------------------- @logger() #调用add函数的时候不想打印日志,就不传参数 def add(*a,**b): #功能函数 sums = 0 for i in range(a) sums + = i #等价 sums = sums + i print (sums) time.sleep(3) add(1,3,5,7,9)