items1 = list ( map ( lambda x : x ** 2 , filter ( lambda x : x % 2 , range ( 1 , 10 ))))
items2 = [x ** 2 for x in range ( 1 , 10 ) if x % 2 ]
from functools import wraps
from time import time
def record_time(func): # 定義裝飾函数的裝飾器
@wraps(func)
def wrapper(*args, **kwargs):
start = time()
result = func(*args, **kwargs)
print(f'{func.__name__} : {time() - start} 秒')
return result
return wrapper
@record_time
def test():
pass
if __name__ == "__main__":
test()
如果裝飾器不希望跟 print 函數耦合,可以編寫帶參數的裝飾器。
from functools import wraps
from time import time
import sys
def record(output): # 定義帶參數 (函數) 的裝飾器
def decorate(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time()
result = func(*args, **kwargs)
output(func.__name__, time() - start)
return result
return wrapper
return decorate
def out(str,float):
print(f'{str} : {float} 秒')
@record(output = out)
def test():
pass
if __name__ == "__main__":
test()
定義裝飾類別(利用 call 方法使得物件可以當成函數調用)
from functools import wraps
from time import time
class Record():
def __init__(self, output):
self.output = output
def __call__(self, func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time()
result = func(*args, **kwargs)
self.output(func.__name__, time() - start)
return result
return wrapper
def out(str,float):
print(f'{str} : {float} 秒')
@Record(out)
def test():
pass
if __name__ == "__main__":
test()
以上兩種也會得到此結果。
範例 - 用裝飾器來實現單例模式 (Singleton)。
在應用這個模式時,單例對象的類別必須保證只有一個實例存在。
許多時候整個系統只需要擁有一個的全局對象,這樣有利於我們協調系統整體的行為。
例如在伺服器程序中,該伺服器的配置數據存放在一個文件中,這些配置數據由一個單例物件統一讀取,然後服務行程 (process) 中的其他對象再通過這個單例獲取這些配置數據。
from functools import wraps
def singleton(cls): # 裝飾類別的裝飾器
instances = {}
@wraps(cls)
def wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return wrapper
@singleton
class test(): # 類別
pass
t1 = test()
t2 = test()
print(t1)
print(t2)
可以看出,雖然進行兩次實例化,但仍為同一個。
單例模式在多線程 (Multithreading) 的應用場合必須小心使用。如果當唯一實例尚未創建時,有兩個線程 (thread) 同時調用創建方法,它們同時沒有檢測到唯一實例的存在,從而同時各自創建了一個實例,這樣就有兩個實例被構造出來,違反了單例模式中實例唯一的原則。
線程安全的單例裝飾器。 解決這個問題的辦法是為已經實例化的變數提供一個互斥鎖。
from functools import wraps
from threading import Lock
def singleton(cls): # 裝飾類別的裝飾器
instances = {}
locker = Lock()
@wraps(cls)
def wrapper(*args, **kwargs):
if cls not in instances:
with locker:
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return wrapper
@singleton
class test(): # 類別
pass