22

フレーム オブジェクトからクラス情報を取得することは可能ですか? ファイル (frame.f_code.co_filename)、関数 (frame.f_code.co_name)、および行番号 (frame.f_lineno) を取得する方法は知っていますが、アクティブなオブジェクトのクラスの名前も取得できるようにしたいと考えています。フレームのインスタンス (またはインスタンスにない場合は None)。

4

5 に答える 5

26

フレーム オブジェクト レベルで、呼び出された実際の 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_localsvalue_dictframe.f_code.co_varnames[:frame.f_code.co_argcount]args

これはまだ慣習のみに依存しているため、移植性がなく、エラーが発生しやすいことに注意してください。

  • 非メソッド関数selfが最初のパラメーター名として使用されている場合、最初のパラメーターget_class_from_frameのクラスが誤って返されます。
  • 記述子を操作するときに誤解を招く可能性があります (アクセスされている実際のインスタンスではなく、記述子のクラスを返します)。
  • @classmethodパラメータを@staticmethodとらずself、記述子で実装されます。
  • そして確かにもっとたくさん

正確に何をしたいかによっては、時間をかけてさらに深く掘り下げ、これらすべての問題の回避策を見つけることができます (返されたクラスにフレーム関数が存在することを確認し、同じソースを共有し、記述子呼び出しを検出することが可能です。クラスメソッドなどについても同じ..)

于 2010-02-08T10:07:51.847 に答える
8

これは少し短いですが、ほぼ同じです。クラス名が利用できない場合は 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
于 2010-03-30T11:14:08.853 に答える
6

同じ問題に直面していたので、この投稿に出くわしました。ただし、すでに挙げたすべての理由から、「自己」メソッドは受け入れられる解決策とは考えていませんでした。

次のコードは、別のアプローチを示しています。フレーム オブジェクトを指定すると、一致するメンバー名とコード ブロックを持つオブジェクトのグローバルを検索します。検索は網羅的ではないため、すべてのクラスが明らかになるわけではありませんが、一致するコードを検証するため、見つかったクラスは探しているクラスになります。

コードの目的は、関数名の先頭にクラス名を追加することです (見つかった場合)。

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__ため、最適化/ハイブリッド化の余地が確実にあることに注意してください。

于 2013-03-29T13:49:04.747 に答える
0

こんにちは、ネクロを許してください。しかし、これらのどれもうまくいかなかったので、ここのスニペットのいくつかに触発されて、代替案を作成しました. これは、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;

それが機能する方法は実際には非常に簡単です。

  1. フレームのグローバル スコープ内のクラスの場合
  2. このクラスに問題の名前を共有するメンバーがいる場合
  3. このメンバーが関数かどうか
  4. 最後に、両方の関数のコードを比較します

Nº4 が true の場合、フレームから取得したコードと同じコードを持つclsメソッドを持つクラスであることがわかります。member

すべて順調ですが、これは完璧ではありません。私がテストした限り、プロパティで装飾されたメソッドでは機能しません。そのコーナーケースをどのように処理するかはまだ完全にはわかりません. しかし、それは私が現時点で必要とするすべての通常の静的メソッドで機能しているので、十分に公平です。

ただし、これは非常に遅いことに注意してください。これは言うまでもありません。私自身のベンチマークによると、通常、100,000 回の呼び出しごとに約 2 ~ 3 秒かかります。これは私の現在のユースケースでは許容されますが、これを一度に数回以上使用する必要がある場合は、最初にいくつかの最適化を行うことをお勧めします. 私はそれをあなたの有能な手に任せます(:

ここで検索エンジンにつまずいた他の誰かが、これが役立つものを見つけてくれることを願っています.

乾杯。

于 2021-03-04T11:58:41.717 に答える