1. 為什么要使用裝飾器
比如下面代碼要增加一個打印時間的功能,可以通過對原函數(shù)進行更改,或者再增加一個函數(shù)完成。
eg:
import time
def f2():
print("This is f2")
增加一個打印時間的功能
a.直接更改原函數(shù)實現(xiàn)
def f2():
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
print("This is f2")
b.通過新增加一個函數(shù)實現(xiàn)
def print_now_time():
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
f2()
但是如果要是有很多個函數(shù),那么就要對很多個函數(shù)重新改寫,或者重新定義一個函數(shù)來實現(xiàn)。
那么有沒有辦法,在保持原有函數(shù)調(diào)用的方法不變,實現(xiàn)增加一個打印時間的功能。那么就引出了裝飾器。
def deco1(func):
def inner():
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
return func()
return inner
@deco1
def f2():
print("This is f2")
f2()
通過定義裝飾器,在不改變原有函數(shù)調(diào)用方法,實現(xiàn)了新的功能。這個是我理解的裝飾器的作用。
2.裝飾器執(zhí)行的順序
eg:
import time
def deco1(func):
print('裝飾器開始運行了!')
def inner():
print('函數(shù)執(zhí)行開始了!')
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
return func()
print('函數(shù)執(zhí)行結(jié)束了!')
print('裝飾器運行結(jié)束了!')
return inner
@deco1
def f2():
print("This is f2")
f2()
運行結(jié)果:
裝飾器開始運行了!
裝飾器運行結(jié)束了!
函數(shù)執(zhí)行開始了!
2020-08-23 10:19:52
This is f2
函數(shù)執(zhí)行結(jié)束了!
通過以上我們可以知道,裝飾器在程序初始化的時候,就已經(jīng)開始運行。但裝飾器里面的函數(shù)是在程序開始執(zhí)行的時候,才開始調(diào)用。
那么如果有多個裝飾器,他們的執(zhí)行順序又是怎么樣的呢?
eg:
import time
def deco1(func):
print('裝飾器1開始運行了!')
def inner():
print('函數(shù)1執(zhí)行開始了!')
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
time.sleep(3)
return func()
print('函數(shù)1執(zhí)行結(jié)束了!')
print('裝飾器1運行結(jié)束了!')
return inner
def deco2(func):
print('裝飾器2開始運行了!')
def inner():
print('函數(shù)2執(zhí)行開始了!')
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
time.sleep(2)
return func()
print('函數(shù)2執(zhí)行結(jié)束了!')
print('裝飾器2運行結(jié)束了!')
return inner
@deco1
@deco2
def f2():
print("This is f2")
運行結(jié)果:
裝飾器2開始運行了!
裝飾器2運行結(jié)束了!
裝飾器1開始運行了!
裝飾器1運行結(jié)束了!
函數(shù)1執(zhí)行開始了!
2020-08-23 10:24:58
函數(shù)2執(zhí)行開始了!
2020-08-23 10:25:01
This is f2
函數(shù)2執(zhí)行結(jié)束了!
函數(shù)1執(zhí)行結(jié)束了!
從上面我們可以看到,裝飾器是從內(nèi)向外開始初始化,裝飾器內(nèi)的程序是從外開始先內(nèi)運行。
3.以上函數(shù)是未帶參數(shù),如果需要裝飾的函數(shù)帶參數(shù),那么裝飾器又是怎么樣的呢?
eg:
import time
def dec3(func):
def inner(*args,**kwargs):
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
return func(*args,**kwargs)
return inner
@dec3
def f3(name):
print('Good morning',name)
f3('Jon')
輸出結(jié)果:
2020-08-23 10:34:14
Good morning Jon
4. 函數(shù)可以帶參數(shù)去執(zhí)行了,那么裝飾器是否可以帶上參數(shù)呢?
eg:
import time
def judeg(times):
def dec4(func):
def inner(*args,**kwargs):
hour=time.localtime().tm_hour - times
if hour >=0:
print('現(xiàn)在距離{times}點已過{hour}小時'.format(times=times,hour=hour))
else:
print('現(xiàn)在距離{times}點還有{hour}小時'.format(times=times,hour=-hour))
return func(*args,**kwargs)
return inner
return dec4
@judeg(12)
def f4(name):
print("Hello",name)
f4('Mike')
運行結(jié)果:
現(xiàn)在距離12點還有1小時
Hello Mike
5. 類裝飾器
eg:
class Foo:
def __init__(self,func):
self._func = func
def __call__(self):
print("裝飾器開始運行!")
self._func()
print("裝飾器運行結(jié)束!")
@Foo
def f1():
print('Hello')
f1()