# 定義一個裝飾器
def set_func(func):
def call_func():
print('————在函數以前添加功能——————')
func()
print('————在函數後面添加功能——————')
return call_func
# 定義一個函數,並添加裝飾器
@set_func # 等價於 func1=set_func(func1)
def func1():
print('____func1____')
# 調用函數
func1()複製代碼
————在函數以前添加功能——————
____func1____
————在函數後面添加功能——————
複製代碼
2. 有參數有返回值得函數
python
# 定義裝飾器
def set_func(func):
def call_func(*args, **kwargs):
print('——————添加功能————————')
return func(*args, **kwargs)
return call_func
# 定義一個函數並進行裝飾
@set_func
def func1(m):
print('____func1____')
return m
# 調用函數
f = func1(100)
print(f)複製代碼
——————添加功能————————
____func1____
100複製代碼
2.帶有參數的裝飾器
import time
# 定義裝飾器
def set_log(log):
def set_func(func):
# 定義log_dict 字典
log_dict = {1: 'error', 2: 'warning'}
def call_func(*args, **kwargs):
# 打開log.txt文件(沒有就建立文件),追加內容
with open('log.txt', 'a', encoding='utf-8') as f:
f.write('%s ---%s---調用了函數%s\n' % (log_dict[log], str(time.ctime()), func.__name__))
return func(*args, **kwargs)
return call_func
return set_func
# 定義一個函數並進行裝飾
@set_log(1)
def func1(m):
print('____func1____')
return m
# 調用函數
f = func1(100)
print(f)複製代碼
____func1____
100
# log.txt 文件內容
error ---Fri Jan 5 22:01:24 2018---調用了函數func1複製代碼
3.一個函數有兩個裝飾器緩存
# 定義裝飾器1
def set_log(func):
print('————開始裝飾sel_log————')
def call_func():
print('___set_log___')
func()
return call_func
# 定義裝飾器2
def set_func(func):
print('————開始裝飾set_func————')
def call_func():
print('___set_func___')
func()
return call_func
# 定義函數,並添加裝飾器
@set_log
@set_func # 等價於 func1=set_func(func1)
def func1():
print('____func1____')複製代碼
————開始裝飾set_func————
————開始裝飾sel_log————
複製代碼
# 調用函數
func1()複製代碼
# 執行結果
————開始裝飾set_func————
————開始裝飾sel_log————
___set_log___
___set_func___
____func1____複製代碼
4. 1、functools.wrapsbash
import time
import functools
# 定義裝飾器
def clock(func):
@functools.wraps(func)
# 使用 functools.wraps裝飾器把相關的屬性從 func複製到 clocked 中,避免遮蓋了被裝飾函數的 __name__ 和 __doc__ 屬性
def clocked(*args, **kwargs):
t0 = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - t0
# 當前執行的函數名稱
name = func.__name__
arg_lst = []
if args:
arg_lst.append(', '.join(repr(arg) for arg in args))
if kwargs:
pairs = ['%s=%r' % (k, w) for k, w in sorted(kwargs.items())]
arg_lst.append(', '.join(pairs))
arg_str = ', '.join(arg_lst)
print('[%0.8fs] %s(%s) -> %r ' % (elapsed, name, arg_str, result))
return result
return clocked複製代碼
2、使用functools.lru_cache作備忘app
functools.lru_cache 是很是實用的裝飾器,它實現了備忘(memoization)功能。這是一 項優化技術,它把耗時的函數的結果保存起來,避免傳入相同的參數時重複計算,代表緩存不會無限制增加,一段時間不用的緩存 條目會被扔掉。
函數
# 用上一個裝飾器clock
@clock
def fib(n):
if n < 2:
return 1
return fib(n-2) + fib(n-1)
if __name__ == '__main__':
fib(5)
# 執行結果
[0.00000000s] fib(1) -> 1
[0.00000000s] fib(0) -> 1
[0.00000000s] fib(1) -> 1
[0.00000000s] fib(2) -> 2
[0.00000000s] fib(3) -> 3
[0.00000000s] fib(0) -> 1
[0.00000000s] fib(1) -> 1
[0.00000000s] fib(2) -> 2
[0.00000000s] fib(1) -> 1
[0.00000000s] fib(0) -> 1
[0.00000000s] fib(1) -> 1
[0.00000000s] fib(2) -> 2
[0.00000000s] fib(3) -> 3
[0.00000000s] fib(4) -> 5
[0.00000000s] fib(5) -> 8
Process finished with exit code 0
複製代碼
# 用functools.lru_cache進行裝飾
@functools.lru_cache()
@clock
def fib(n):
if n < 2:
return 1
return fib(n-2) + fib(n-1)if __name__ == '__main__':
fib(5)# 執行結果
[0.00000000s] fib(1) -> 1
[0.00000000s] fib(0) -> 1
[0.00000000s] fib(2) -> 2
[0.00100088s] fib(3) -> 3
[0.00000000s] fib(4) -> 5
[0.00100088s] fib(5) -> 8
複製代碼
3、參數選擇functools.lru_cache(maxsize=128, typed=False)
性能
maxsize 參數指定存儲多少個調用的結果。緩存滿了以後,舊的結果會被扔掉,騰出空間。 爲了獲得最佳性能,maxsize 應該設爲 2 的冪。typed 參數若是設爲 True,把不一樣參數類型 獲得的結果分開保存,即把一般認爲相等的浮點數和整數參數(如 1 和 1.0)區分開。順 便說一下,由於 lru_cache 使用字典存儲結果,並且鍵根據調用時傳入的定位參數和關鍵 字參數建立,因此被 lru_cache 裝飾的函數,它的全部參數都必須是可散列的。
優化
4、單分派泛函數singledispatch
ui
能夠把總體方案拆成多個模塊,甚至能夠爲你沒法修改的類提供專門的函數,使用@singledispatch
裝飾的函數會變成泛函數spa
singledispatch
:標記處理object類型的基函數 @<<base_function>>.register(<<type>>)
裝飾 _
是個不錯的選擇,簡單明瞭 register
裝飾器,讓同一個函數支持不一樣類型from functools import singledispatch
@singledispatch
def show(obj):
print(obj, type(obj), "obj")
# 參數字符串
@show.register(str)
def _(text):
print(text, type(text), "str")
# 參數int
@show.register(int)
def _(n):
print(n, type(n), "int")
# 參數元祖或者字典都可
@show.register(tuple)
@show.register(dict)
def _(tup_dic):
print(tup_dic, type(tup_dic), "int")
if __name__ == '__main__':
show(1)
show("xx")
show([1])
show((1, 2, 3))
show({"a": "b"})
# 執行結果
1 <class 'int'> int
xx <class 'str'> str
[1] <class 'list'> obj
(1, 2, 3) <class 'tuple'> int
{'a': 'b'} <class 'dict'> int
複製代碼