フレーム オブジェクトからクラス情報を取得することは可能ですか? ファイル (frame.f_code.co_filename)、関数 (frame.f_code.co_name)、および行番号 (frame.f_lineno) を取得する方法は知っていますが、アクティブなオブジェクトのクラスの名前も取得できるようにしたいと考えています。フレームのインスタンス (またはインスタンスにない場合は None)。
5 に答える
フレーム オブジェクト レベルで、呼び出された実際の python 関数オブジェクトを見つける方法があるとは思えません。
ただし、コードが一般的な規則 (メソッドのインスタンス パラメータの名前付け) に依存している場合self
は、次のようにすることができます。
def get_class_from_frame(fr):
import inspect
args, _, _, value_dict = inspect.getargvalues(fr)
# we check the first parameter for the frame function is
# named 'self'
if len(args) and args[0] == 'self':
# in that case, 'self' will be referenced in value_dict
instance = value_dict.get('self', None)
if instance:
# return its class
return getattr(instance, '__class__', None)
# return None otherwise
return None
を使用したくない場合は、 の代わりにandをgetargvalues
直接使用できます。frame.f_locals
value_dict
frame.f_code.co_varnames[:frame.f_code.co_argcount]
args
これはまだ慣習のみに依存しているため、移植性がなく、エラーが発生しやすいことに注意してください。
- 非メソッド関数
self
が最初のパラメーター名として使用されている場合、最初のパラメーターget_class_from_frame
のクラスが誤って返されます。 - 記述子を操作するときに誤解を招く可能性があります (アクセスされている実際のインスタンスではなく、記述子のクラスを返します)。
@classmethod
パラメータを@staticmethod
とらずself
、記述子で実装されます。- そして確かにもっとたくさん
正確に何をしたいかによっては、時間をかけてさらに深く掘り下げ、これらすべての問題の回避策を見つけることができます (返されたクラスにフレーム関数が存在することを確認し、同じソースを共有し、記述子呼び出しを検出することが可能です。クラスメソッドなどについても同じ..)
これは少し短いですが、ほぼ同じです。クラス名が利用できない場合は None を返します。
def get_class_name():
f = sys._getframe(1)
try:
class_name = f.f_locals['self'].__class__.__name__
except KeyError:
class_name = None
return class_name
同じ問題に直面していたので、この投稿に出くわしました。ただし、すでに挙げたすべての理由から、「自己」メソッドは受け入れられる解決策とは考えていませんでした。
次のコードは、別のアプローチを示しています。フレーム オブジェクトを指定すると、一致するメンバー名とコード ブロックを持つオブジェクトのグローバルを検索します。検索は網羅的ではないため、すべてのクラスが明らかになるわけではありませんが、一致するコードを検証するため、見つかったクラスは探しているクラスになります。
コードの目的は、関数名の先頭にクラス名を追加することです (見つかった場合)。
def get_name( frame ):
code = frame.f_code
name = code.co_name
for objname, obj in frame.f_globals.iteritems():
try:
assert obj.__dict__[name].func_code is code
except Exception:
pass
else: # obj is the class that defines our method
name = '%s.%s' % ( objname, name )
break
return name
派生クラスのキャッチを防ぐために、__dict__
代わりにを使用することに注意してください。getattr
self = frame.f_locals['self']; obj = self.__class__
さらに、一致する場合、またはそれ以上の場合はグローバル検索を回避できるobj in self.__class__.__bases__
ため、最適化/ハイブリッド化の余地が確実にあることに注意してください。
こんにちは、ネクロを許してください。しかし、これらのどれもうまくいかなかったので、ここのスニペットのいくつかに触発されて、代替案を作成しました. これは、Python 3.7 のクラス メソッドに対してどのように実行したかです。
import inspect;
def QLNAME(frame):
code = frame.f_code;
name = code.co_name;
qual = None;
for cls in ( obj for obj in frame.f_globals.values() #
if inspect.isclass(obj) ):
if hasattr(cls, name):
member = getattr(cls, name);
if not inspect.isfunction(member): continue;
if member.__code__ == code:
qual = member.__qualname__;
break;
return qual;
それが機能する方法は実際には非常に簡単です。
- フレームのグローバル スコープ内のクラスの場合
- このクラスに問題の名前を共有するメンバーがいる場合
- このメンバーが関数かどうか
- 最後に、両方の関数のコードを比較します
Nº4 が true の場合、フレームから取得したコードと同じコードを持つcls
メソッドを持つクラスであることがわかります。member
すべて順調ですが、これは完璧ではありません。私がテストした限り、プロパティで装飾されたメソッドでは機能しません。そのコーナーケースをどのように処理するかはまだ完全にはわかりません. しかし、それは私が現時点で必要とするすべての通常の静的メソッドで機能しているので、十分に公平です。
ただし、これは非常に遅いことに注意してください。これは言うまでもありません。私自身のベンチマークによると、通常、100,000 回の呼び出しごとに約 2 ~ 3 秒かかります。これは私の現在のユースケースでは許容されますが、これを一度に数回以上使用する必要がある場合は、最初にいくつかの最適化を行うことをお勧めします. 私はそれをあなたの有能な手に任せます(:
ここで検索エンジンにつまずいた他の誰かが、これが役立つものを見つけてくれることを願っています.
乾杯。