Open Pin-Jiun opened 1 year ago
decorators 多層的話是採 ”recursive” 的方式處理,如果一個 function 有兩個以上的 decorators ,邏輯上則會先合併「最靠近」的 decorator 吐出新的 function 再由上面一個的 decorator 吃進去!
def print_func_name(func):
def warp_1():
print("Now use function '{}'".format(func.__name__))
func()
return warp_1
def print_time(func):
import time
def warp_2():
print("Now the Unix time is {}".format(int(time.time())))
func()
return warp_2
@print_func_name
@print_time
def dog_bark():
print("Bark !!!")
if __name__ == "__main__":
dog_bark()
# > Now use function 'warp_2'
# > Now the Unix time is 1541239747
# > Bark !!!
所以 dog_bark() 會先被 @print_time 吃進去,然後吐出一個叫做 wrap_2 的function,而這個 warp_2 function 又會被 @print_func_name 吃進去,吐出一個叫做 wrap_1 的 function。
所以最後執行的結果順序是先 print Now use function 'wrap_2' 再 print Now the Unix time is 1541239747 。而且你會發現由於最外層的 @print_func_name 真正吃進去的 function 是已經被 @print_time 修飾過的 function,所以 print 的是Now use function 'wrap_2' 而不是 Now use function 'dog_bark' !!
def foo():
return "bar"
如果我們 print(foo),會得到 “function foo at 0x1028831e0” 表示 foo 是一個變數名,並且指向一個函式物件 (object) 。 如果要調用函式的話,則加上(), foo(),即可調用函式。
def foo():
return "bar"
print(foo) # 變數名
print(foo()) # 函式物件
首先我們在 def timer(func): 將 func 變數名稱傳入,接下來定義 def wrap(sleep_time) 函式,並且在裡面將剛剛傳入的 func(sleep_time) 調用,這樣就完成一個簡單的裝飾詞囉!
import time
def timer(func):
def wrap(sleep_time):
t_start = time.time()
func(sleep_time)
t_end = time.time()
t_count = t_end - t_start
print('[花費時間]', t_count)
return wrap
def dosomething(sleep_time):
print('do some thing')
time.sleep(sleep_time)
foo = timer(dosomething)
foo(3)
>>> do some thing
>>> [花費時間] 3.004279136657715
如果不想寫成 foo = timer(dosomething),只需要加上 @timer,並直接調用 dosomething() 函式執行
def timer(func):
def wrap(sleep_time):
t_start = time.time()
func(sleep_time)
t_end = time.time()
t_count = t_end - t_start
print(‘[花費時間]’, t_count)
return wrap
@timer
def dosomething(sleep_time):
print(‘do some thing’)
time.sleep(sleep_time)
dosomething(3)
Decorator
其功能是用來輔助其他function的運作 Decorator也是一個function, 所以最外圍的語法和def function相同
執行順序: 1.呼叫function
f()
2.此時發現@ 裝飾器特殊語法, 會先跳至裝飾器 3.f
會被當成parameter傳至callbacl_function
4.執行裝飾器內部的code :inner_function()
5.執行完畢, 藉由callbacl_function()
跳回原本的f()
再加上參數
實際應用例子