デコレータ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
これは非常に退屈なデコレータであり、これら、キャッシャー、ロガー、ものを注入するもの、ベンチマークなどが12個ほどあります。ifステートメントで簡単に拡張できますが、これは悪い選択のようです。それから私はたくさんのデコレータを変更しなければならないので、それはまったく面白くありません。
じゃあ何をすればいいの?1つ上のレベルに進みましょう。デコレータをデコレータできるデコレータがあるとしましょう。このデコレータは次のようになります。
@point_cut_decorator(logger)
def my_oddly_behaving_function
このデコレータはロガーを受け入れますが、これはあまり興味深い事実ではありません。ただし、ロガーをmy_oddly_behaving_functionに適用するかどうかを選択するのに十分な機能もあります。アスペクト指向プログラミングのいくつかの側面があるため、私はそれをpoint_cut_decoratorと呼びました。ポイントカットは、いくつかのコード(アドバイス)を実行フローと織り交ぜる必要がある場所のセットです。ポイントカットの定義は通常、1か所にあります。この手法は非常に似ているようです。
決定ロジックをどのように実装できますか。さて、私はデコレータ、デコレータ、ファイル、名前を受け入れる関数を作成することを選択しました。これは、デコレータを適用する必要があるかどうかだけを言うことができます。これらは座標であり、場所を非常に正確に特定するのに十分です。
これはpoint_cut_decoratorの実装です。私は決定関数を単純な関数として実装することを選択しました。これを拡張して、設定または構成から決定させることができます。4つの座標すべてに正規表現を使用すると、非常に何かが発生します。強力:
from functools import wraps
myselectorは決定関数であり、trueの場合、デコレータは適用され、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を返し、ルールが一致しない場合はfalseを返します。本番環境でルールを空にすることで、アプリケーションの速度が大幅に低下することはありません。
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