Python:如何从'frame'对象中获取类的信息?

25 投票
6 回答
17237 浏览
提问于 2025-04-15 18:54

有没有办法从一个框架对象中获取任何类的信息?我知道怎么获取文件名(frame.f_code.co_filename)、函数名(frame.f_code.co_name)和行号(frame.f_lineno),但我还想知道如何获取当前框架中活动对象实例的类名(如果没有实例的话就返回None)。

6 个回答

6

我刚看到这个帖子,因为我也遇到了同样的问题。我认为使用'self'方法并不是一个合适的解决方案,原因已经在之前的讨论中提到过了。

下面的代码展示了一种不同的做法:给定一个框架对象,它会在全局范围内搜索一个具有匹配成员名称和代码块的对象。这个搜索并不是特别全面,所以可能并不是所有的类都会被找到,但找到的类应该是我们想要的,因为我们会验证匹配的代码。

这段代码的目的是在找到的情况下,把函数名加上它的类名:

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__或更深层次的内容,那么就可以避免全局搜索,所以这里还有优化和混合的空间。

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
32

我不认为在框架对象层面上,有什么方法可以找到实际被调用的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

如果你不想使用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参数,并且是通过描述符实现的。
  • 还有很多其他问题

根据你想要做的具体事情,你可能需要花一些时间深入研究,找到这些问题的解决方法(你可以检查返回的类中是否存在框架函数,并且共享相同的源代码,检测描述符调用是可能的,类方法也是如此,等等)。

撰写回答