“”“”
什么是裝飾器?
"""
還是通過一個例子來慢慢說明
先看下面的例子
def func_1(x):
return x*2
def fun_2(x):
return x*3
def fun_3(x, y i, j):
return x(i)+y(j)
r = func_3(func_1,func_2,2,3) #把函數引用作為參數傳遞給func_3
print(r)
#通過上面的例子明白:函數的參數可以是函數,也可以是一個類,其實可以是任何類型
def runtime_noargs():
pass
@runtime_noargs #這里就是一個裝飾器,裝飾器就是一個閉包函數,回憶下上篇文章的閉包感念
def function_demo1()
print("demo1函數被運行")
那么是如何把某種功能附加給上面的裝飾器,讓它幫助被裝飾的函數實現某種功能的呢?
我們先對裝飾器函數進行修改
import time
def runtime_noargs(function_name): #將來這里的function_name接受被裝飾的函數名
def wrapper():
start_time = time.time()
function_name() #在這里執行被裝飾器裝飾的函數
end_time = time.time()
print(end_time - start_time)
return wrapper
@runtime_noargs #當裝飾器用來裝飾某函數時,被裝飾的函數名被自動傳參給裝飾器函數
def function_demo1()
time.sleep(1)
print("demo1函數被運行")
function_demo1() #可以使用debug單步運行模式來看看函數的具體執行步驟
上面是一個沒有參數的函數,通過裝飾器來裝飾的,那么有參數的函數如何通過裝飾器來裝飾呢?
def args_is_string(function_name):
def wrapper(a):
t=type(a)
if not isinstance(t(), str):
print("參數錯誤")
else:
funtion_name(a)
return wrapper
@args_is_string #通過一個裝飾器函數來限制被裝飾函數輸入的參數只能是字符串
def function_demo2(args): #函數里的參數和裝飾器函數里的內部函數wrapper參數對應,這樣 print(args) #args參數就自動傳給了裝飾器中內部函數的參數a上,這是python的 #規則
function_demo2("aaaa")
上面的例子中,被裝飾的函數只能傳一個參數,那么要傳多個參數呢?
通過一個例子來說明如何實現多個參數的函數的是如何被裝飾的
def many_args(function_name):
def wrapper(*args):
print(*args) #不定長參數這里一個*,打印時需要
function_name(*args)
return wrapper
@many_args
def function_demo3(*args) #*args可以接受不定長參數,可以接受若干個參數
print(*args)
function_demo3(1,2,3,4,5,6)
如果關鍵字參數這種怎么辦呢?
def dict_args(funtion_name):
def wrapper(**kwargs):
print(kwargs) #不定長字典類型的參數,兩個*,在打印時不需要加*,注意和上面的區別
function_name(**kwargs)
return wrapper
@dict_args
def function_demo4(**kwargs): #**kwargs用來傳不定長的字典形式參數
print(kwargs)
funtion_demo4(name = "fang", age = 10, address = "北京")
如果是混合型的參數呢?
def combo_args(function_name):
def wrapper(*args, **kwargs):
print(*args,kwargs)
return warpper
@combo_args
def function_demo5(*args, **kwargs):
pass
function_demo5(1,2,name="fang",age = "10",address="北京")
上面是裝飾器的基本使用方法。
再介紹一種進階版的裝飾器,監控函數運行是否超時
def max_runtime(function_time);
def out_wrapper(funtion_name):
def wrapper(*args, **kwargs):
start_time = time.time()
i = function_name(*args,**kwargs) #如果函數需要返回值,這里必須由接住函數 #返回值
end_time = time.time()
use_time = end_time - start_time
if use_time > timeout:
raise RuntimeError("函數運行超時")
return i #這里必須把函數返回值返回去,即便在被裝飾的函數本體里已經寫了 #return
return wrapper
return out_wrapper
@max_runtime(timeout=1)
def function_demo6(*args, **kwargs):
time.sleep(2)
print("demo6運行")
return 1
result = function_demo6()
print(result)
上面的這個例子告訴我們,裝飾器后面帶參數時,裝飾器的閉包函數體就要多寫一層函數,見上圖之間的對應關系。