我認爲你應該使用裝飾器a來裝飾裝飾器b,它可以讓你使用判定函數來打開或關閉裝飾器b。
這聽起來很複雜,但這個想法很簡單。
因此,讓我們假設你有一個裝飾記錄:
from functools import wraps
def logger(f):
@wraps(f)
def innerdecorator(*args, **kwargs):
print (args, kwargs)
res = f(*args, **kwargs)
print res
return res
return innerdecorator
這是一個很無聊的裝飾,我有十幾這些,cachers,記錄器,東西注入的東西,標杆等我可以很容易用if語句擴展它,但這似乎是一個不好的選擇;因爲那時我必須更換十幾個裝飾器,這根本不好玩。
所以,我們要做什麼呢?讓我們走高一級。假設我們有一個裝飾器,可以裝飾裝飾器?這個裝飾器看起來像這樣:
@point_cut_decorator(logger)
def my_oddly_behaving_function
這個裝飾器接受記錄器,這不是一個非常有趣的事實。但是它也有足夠的能力來選擇記錄器是否應用於my_oddly_behaving_function。我將它稱爲point_cut_decorator,因爲它具有面向方面編程的某些方面。減分是一組位置,其中一些代碼(建議)必須與執行流程交織在一起。點削減的定義通常在一個地方。這種技術似乎非常相似。
我們該如何實現它的決策邏輯。那麼我選擇了一個函數,它接受裝飾器,裝飾器,文件和名稱,它只能說如果一個裝飾器應該適用或不適用。這些座標是非常精確的,可以精確定位位置。
這是point_cut_decorator的實現,我選擇將決定函數實現爲一個簡單的函數,可以將它擴展爲讓它根據您的設置或配置決定,如果您對所有4個座標使用正則表達式,則會結束up:
from functools import wraps
myselector是決定函數,對於真實的裝飾器應用於false,它不適用。參數是文件名,模塊名稱,裝飾對象以及裝飾器。這允許我們以細粒度的方式切換行爲。
def myselector(fname, name, decoratee, decorator):
print fname
if decoratee.__name__ == "test" and fname == "decorated.py" and decorator.__name__ == "logger":
return True
return False
該裝飾功能,檢查myselector如果myselector說下去,它將裝飾應用到的功能。
def point_cut_decorator(d):
def innerdecorator(f):
@wraps(f)
def wrapper(*args, **kwargs):
if myselector(__file__, __name__, f, d):
ps = d(f)
return ps(*args, **kwargs)
else:
return f(*args, **kwargs)
return wrapper
return innerdecorator
def logger(f):
@wraps(f)
def innerdecorator(*args, **kwargs):
print (args, kwargs)
res = f(*args, **kwargs)
print res
return res
return innerdecorator
這是你如何使用它:
@point_cut_decorator(logger)
def test(a):
print "hello"
return "world"
test(1)
編輯:
這是正則表達式的方法我談到:
from functools import wraps
import re
,你可以看,我可以指定一些規則,這決定了一個裝飾器應適用與否:
rules = [{
"file": "decorated.py",
"module": ".*",
"decoratee": ".*test.*",
"decorator": "logger"
}]
然後我遍歷所有的規則,並返回True如果規則匹配或假,如果規則不匹配。通過制定規則在生產空,這會不會你的應用程序減慢太多:
def myselector(fname, name, decoratee, decorator):
for rule in rules:
file_rule, module_rule, decoratee_rule, decorator_rule = rule["file"], rule["module"], rule["decoratee"], rule["decorator"]
if (
re.match(file_rule, fname)
and re.match(module_rule, name)
and re.match(decoratee_rule, decoratee.__name__)
and re.match(decorator_rule, decorator.__name__)
):
return True
return False
這不允許每個文件切換,並且如果裝飾器來自標準庫或以其他方式無法編輯,則必須在每個裝飾器的包裝中完成。 – engineerC