[解決済み] Python クラスのすべてのメソッドを指定されたデコレータで取得する方法
質問
与えられたクラスAで、@decorator2で装飾されたすべてのメソッドを取得するにはどうすればよいですか?
class A():
def method_a(self):
pass
@decorator1
def method_b(self, b):
pass
@decorator2
def method_c(self, t=5):
pass
どのように解決するのですか?
方法1:基本的なデコレータの登録
この質問にはすでにこちらで回答しています。 Pythonで配列のインデックスで関数を呼び出す =)
方法2:ソースコードのパース
を制御できない場合は クラス 定義 と仮定するのは一つの解釈で、これは 不可能 (code-reading-reflectionなしで)です。例えば、デコレータは単に関数を変更せずに返すだけのno-opデコレータ(私のリンク先の例のように)である可能性があるからです。(それでも、もしあなたがデコレータをラップ/再定義することを許したなら、以下を参照してください。 方法3: デコレーターを "self-aware" に変換する。 を参照してください。)
とんでもなくひどいハックですが、あなたは
inspect
モジュールを使ってソースコードそのものを読み、それをパースすることができます。これはインタラクティブなインタープリタでは動作しません。なぜなら、inspect モジュールはインタラクティブモードではソースコードの提供を拒否するからです。しかし、以下は概念的な証明です。
#!/usr/bin/python3
import inspect
def deco(func):
return func
def deco2():
def wrapper(func):
pass
return wrapper
class Test(object):
@deco
def method(self):
pass
@deco2()
def method2(self):
pass
def methodsWithDecorator(cls, decoratorName):
sourcelines = inspect.getsourcelines(cls)[0]
for i,line in enumerate(sourcelines):
line = line.strip()
if line.split('(')[0].strip() == '@'+decoratorName: # leaving a bit out
nextLine = sourcelines[i+1]
name = nextLine.split('def')[1].split('(')[0].strip()
yield(name)
うまくいった!?
>>> print(list( methodsWithDecorator(Test, 'deco') ))
['method']
パースとpythonの構文に注意する必要があることに注意してください、例えば
@deco
と
@deco(...
は有効な結果ですが
@deco2
は返されないはずです。
'deco'
. の公式の Python 構文によると、以下のようになります。
http://docs.python.org/reference/compound_stmts.html
の公式な構文によると、デコレータは以下のようになります。
decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE
のようなケースに対処する必要がなくなり、安堵のため息をついています。
@(deco)
. しかし、これでもまだ、たとえば
@getDecorator(...)
のような複雑なデコレータがある場合、これはまだあまり役に立ちません。
def getDecorator():
return deco
このように、コードを解析するこの最善策では、このようなケースを検出することはできません。とはいえ、この方法を使う場合、本当に必要なのは、定義の中でメソッドの上に書かれていることで、この場合は
getDecorator
.
仕様によれば、以下のような記述も有効です。
@foo1.bar2.baz3(...)
をデコレータとして使用することも可能です。このメソッドを拡張して、それを扱うことができます。また、このメソッドを拡張して
<function object ...>
を返すように拡張することもできるかもしれません。しかし、この方法はハック的でひどいものです。
方法3: デコレーターを "self-aware" に変換する。
を制御できない場合は
デコレータ
定義
(これはあなたが望むことの別の解釈です) であれば、 デコレータがどのように適用されるかをあなたが制御できるので、 これらの問題はすべて解決します。このように、デコレータを修正するには
を包む
をラップすることで、デコレータを変更できます。
を作成します。
デコレータを作成し
その
を使って関数を装飾することができます。もう一度言いますが、自分がコントロールできないデコレータを装飾するデコレータを作り、それを "enlightning"して、この例では以前やっていたことをさせるのですが、しかし
また
を追加します。
.decorator
メタデータプロパティを追加し、「この関数はデコレートされているかどうか?そして
では
を使えば、クラスのメソッドを繰り返し実行し、デコレータが適切な
.decorator
プロパティを持つかどうかを確認するだけです! =) ここで実証されているように
def makeRegisteringDecorator(foreignDecorator):
"""
Returns a copy of foreignDecorator, which is identical in every
way(*), except also appends a .decorator property to the callable it
spits out.
"""
def newDecorator(func):
# Call to newDecorator(method)
# Exactly like old decorator, but output keeps track of what decorated it
R = foreignDecorator(func) # apply foreignDecorator, like call to foreignDecorator(method) would have done
R.decorator = newDecorator # keep track of decorator
#R.original = func # might as well keep track of everything!
return R
newDecorator.__name__ = foreignDecorator.__name__
newDecorator.__doc__ = foreignDecorator.__doc__
# (*)We can be somewhat "hygienic", but newDecorator still isn't signature-preserving, i.e. you will not be able to get a runtime list of parameters. For that, you need hackish libraries...but in this case, the only argument is func, so it's not a big issue
return newDecorator
のデモ
@decorator
:
deco = makeRegisteringDecorator(deco)
class Test2(object):
@deco
def method(self):
pass
@deco2()
def method2(self):
pass
def methodsWithDecorator(cls, decorator):
"""
Returns all methods in CLS with DECORATOR as the
outermost decorator.
DECORATOR must be a "registering decorator"; one
can make any decorator "registering" via the
makeRegisteringDecorator function.
"""
for maybeDecorated in cls.__dict__.values():
if hasattr(maybeDecorated, 'decorator'):
if maybeDecorated.decorator == decorator:
print(maybeDecorated)
yield maybeDecorated
うまくいった!?
>>> print(list( methodsWithDecorator(Test2, deco) ))
[<function method at 0x7d62f8>]
ただし、quot;registered decorator"は、quot;registered decoratorと同じように
一番外側のデコレータ
でなければならず、そうでなければ
.decorator
属性のアノテーションが失われてしまいます。例えば
@decoOutermost
@deco
@decoInnermost
def func(): ...
というメタデータのみ見ることができます。
decoOutermost
が公開するメタデータしか見ることができません。
補足: 上記の方法で
.decorator
を追跡することができます。
適用されたデコレータや入力関数、デコレータファクトリの引数のスタック全体を追跡するR.original = func
@foo
@bar(...)
foo
関連
-
[解決済み] Pythonで現在時刻を取得する方法
-
[解決済み] pipでPythonの全パッケージをアップグレードする方法
-
[解決済み] Pythonで静的なクラス変数は可能ですか?
-
[解決済み] Pythonの静的メソッド?
-
[解決済み] フルパスでモジュールをインポートするには?
-
[解決済み] Pythonの@propertyデコレーターはどのように機能するのでしょうか?
-
[解決済み】ネストされたディレクトリを安全に作成するには?
-
[解決済み】2つの辞書を1つの式でマージする(辞書の和をとる)には?)
-
[解決済み] SQLAlchemy: 日付フィールドをフィルタリングする方法は?
-
[解決済み] CSVデータを処理する際、1行目のデータを無視する方法を教えてください。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Pythonです。未束縛のメソッドを束縛する?
-
[解決済み] Pythonのキャッシュライブラリはありますか?
-
[解決済み] 値で列挙名を取得する [重複]。
-
[解決済み] 文字列のリストを内容に基づいてフィルタリングする
-
[解決済み] python-requests モジュールからのすべてのリクエストをログに記録します。
-
[解決済み] Pythonでマルチプロセッシングキューを使うには?
-
[解決済み] Pythonによる一対のクロスプロダクト [重複] (英語)
-
[解決済み] if 節の終了方法
-
[解決済み] Django filter queryset __in for *every* item in list
-
[解決済み] Python の sorted() はどのようなアルゴリズムを使っているのですか?重複