前言
前面一篇對python裝飾器有了初步的了解了,但是還不夠完美,領導看了后又提出了新的需求,希望運行的日志能顯示出具體運行的哪個函數。
name__和__doc
__name__
用於獲取函數的名稱,__doc__
用於獲取函數的docstring內容(函數的注釋)
import time
def func_a(a):
'''func_a --> hello'''
print("hello"+a)
time.sleep(0.5)
return True
def func_b(b, c="xx"):
'''func_b --> world'''
print("world"+b+c)
time.sleep(0.8)
return True
if __name__ == '__main__':
print(func_a.__name__) # 結果 func_a
print(func_a.__doc__) # func_a --> hello
print(func_b.__name__) # func_b
print(func_b.__doc__) # func_b --> world
裝飾器加函數名稱日志
在裝飾器里面添加2行代碼,打印正在運行函數的名稱和docstring內容
import time
def runtime(func):
'''runtime decorators'''
def wrapper(*args, **kwargs):
'''wrapper inner fuction'''
print("running function : %s" % func.__name__)
print("docstring: %s" % func.__doc__)
start = time.time()
f = func(*args, **kwargs) # 原函數
end = time.time()
print("運行時長:%.4f 秒" % (end-start))
return f
return wrapper
@runtime
def func_a(a):
'''func_a --> hello'''
print("hello"+a)
time.sleep(0.5)
return True
@runtime
def func_b(b, c="xx"):
'''func_b --> world'''
print("world"+b+c)
time.sleep(0.8)
return True
if __name__ == '__main__':
func_a("a")
print(func_a.__name__)
print(func_a.__doc__)
運行結果
running function : func_a
docstring: func_a --> hello
helloa
運行時長:0.5008 秒
wrapper
wrapper inner fuction
從運行的結果可以看出,func_a.__name__
運行的結果是wrapper, func_a.__doc__
運行的結果是wrapper inner fuction。
也就是說被裝飾后的函數其實已經是另外一個函數了(函數名等函數屬性會發生改變),那這個問題如何解決呢?
這就需要用到functools里面的一個wraps函數了
functools
當func_a函數被裝飾后,導致了一個副作用:自身的函數屬性和docstring內容變成了wrapper函數的屬性了。
這里需用到functools里面的一個wraps的裝飾器來消除這樣的副作用。
import time
from functools import wraps
def runtime(func):
'''runtime decorators'''
@wraps(func)
def wrapper(*args, **kwargs):
'''wrapper inner fuction'''
print("running function : %s" % func.__name__)
print("docstring: %s" % func.__doc__)
start = time.time()
f = func(*args, **kwargs) # 原函數
end = time.time()
print("運行時長:%.4f 秒" % (end-start))
return f
return wrapper
只需在wrapper函數上加上@wraps(func)
即可解決
運行結果
running function : func_a
docstring: func_a --> hello
helloa
運行時長:0.5004 秒
func_a
func_a --> hello
類裝飾器
帶參數的裝飾器,可以寫成類裝飾器
import time
from functools import wraps
class runtime(object):
'''runtime class decorators'''
def __init__(self, slowly=1):
self.slowly = slowly
def __call__(self, func):
@wraps(func)
def wrapper(*args, **kwargs):
'''wrapper inner fuction'''
print("running function : %s" % func.__name__)
print("docstring: %s" % func.__doc__)
start = time.time()
f = func(*args, **kwargs) # 原函數
end = time.time()
t = end-start
time.sleep((self.slowly-1)*t) # 延遲效果
new_end = time.time()
print("運行時長:%.4f 秒" % (new_end-start))
return f
return wrapper
@runtime(1.5)
def func_a(a):
'''func_a --> hello'''
print("hello"+a)
time.sleep(0.5)
return True
@runtime()
def func_b(b, c="xx"):
'''func_b --> world'''
print("world"+b+c)
time.sleep(0.8)
return True
if __name__ == '__main__':
func_a("a")
print(func_a.__name__)
print(func_a.__doc__)
運行結果
running function : func_a
docstring: func_a --> hello
helloa
運行時長:0.7522 秒
func_a
func_a --> hello
python自動化交流 QQ群:779429633