Python:如何从'frame'对象中检索类信息?

Kev*_*tle 17 python introspection

是否可以从框架对象中检索任何类信息?我知道如何获取文件(frame.f_code.co_filename),函数(frame.f_code.co_name)和行号(frame.f_lineno),但希望能够获取活动对象的类的名称框架的实例(如果不在实例中,则为None).

Clé*_*ent 19

我不相信,在帧对象级别,有任何方法可以找到已调用的实际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
Run Code Online (Sandbox Code Playgroud)

如果你不想使用getargvalues,可以直接使用frame.f_locals,而不是value_dictframe.f_code.co_varnames[:frame.f_code.co_argcount]代替args.

请记住,这仍然只依赖于约定,因此它不可移植,并且容易出错:

  • 如果非方法函数self用作第一个参数名,那么get_class_from_frame将错误地返回第一个参数的类.
  • 使用描述符时可能会产生误导(它将返回描述符的类,而不是正在访问的实际实例).
  • @classmethod并且@staticmethod不会使用self参数并使用描述符实现.
  • 肯定还有很多

根据您想要做什么,您可能需要花一些时间深入挖掘并找到所有这些问题的解决方法(您可以检查返回类中存在的框架函数并共享相同的源,检测描述符调用是否可行,类方法等相同..)

  • 要在列表中添加一个,请注意'self'可能是派生类的实例,可能不是我们感兴趣的实例. (3认同)

小智 7

这有点短,但大致相同.如果类名不可用,则返回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
Run Code Online (Sandbox Code Playgroud)

  • @LucioPaiva不起作用.f_locals中没有键''__class __'`. (2认同)

ger*_*jan 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
Run Code Online (Sandbox Code Playgroud)

注意使用__dict__代替getattr来防止派生类被捕获。

进一步注意,如果self = frame.f_locals['self']; obj = self.__class__给出匹配或任何obj in self.__class__.__bases__或更深的匹配,则可以避免全局搜索,因此肯定有优化/混合的空间。