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