2010-02-04 55 views
15

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

回答

16

我不相信,在框架对象级别,有任何方法可以找到已调用的实际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_dictframe.f_code.co_varnames[:frame.f_code.co_argcount]而不是args

请记住,这仍然只是依靠惯例,所以它是不可移植的,并且容易出错:

  • 如果非法功能使用self作为第一个参数名称,然后get_class_from_frame将错误返回第一个参数的类。
  • 使用描述符时它可能会引起误解(它将返回描述符的类,而不是被访问的实际实例)。
  • @classmethod@staticmethod将不会采取self参数,并与描述符一起实现。
  • ,肯定有很多更取决于正是你想做的事

,你可能要花费一些时间来深入挖掘,并找到解决方法的所有这些问题(你可以检查框功能存在于返回的类和共享相同的来源,检测描述符调用是可能的,类方法相同等。)

+0

感谢您的回答,Clément;它是详细和周到的。我仍然希望获得不止一个回应!但是,如果没有,这一个将足以... – 2010-02-08 23:32:17

+0

好吧,等待足够长。这是一个很好的答案!我曾希望能从框架结构中获得更好的支持,但事实就是如此。再次感谢克莱门特! – 2010-02-11 23:16:19

+1

要添加一个到列表中,请注意'自己'可能是一个派生类的实例,可能不是我们感兴趣的类。 – gertjan 2013-03-29 13:38:08

7

这有点短,但大致相同。如果班级名称不可用,则返回无。

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 
+0

好的答案!更好的是,你可以做''f.f_locals ['__ class __'] .__ name__'',它也应该覆盖''classmethod''和''staticmethod''的情况。 – 2015-01-07 21:38:06

+2

@LucioPaiva不起作用。在f_locals中没有关键的'__class __'。 – Pithikos 2015-05-15 16:01:32

2

我刚刚遇到这篇文章,因为我遇到了同样的问题。然而,我并没有将“自我”方法视为可接受的解决方案,因为已经列出的所有原因。

下面的代码演示了一种不同的方法:给定一个框架对象,它在全局变量中搜索匹配成员名称和代码块的对象。搜索并不全面,所以有可能不是所有的类都会被发现,但是找到的类应该是我们正在寻找的类,因为我们验证了匹配的代码。代码

对象是在前面加上函数名与它的类名,如发现:

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__或更深,则可以避免全局搜索,所以确实存在优化/杂交的空间。

1

如果一个方法是一个类方法,该类将是第一个参数。这将打印出每个调用堆栈帧的第一个arg的类型(如果存在):

def some_method(self): 
     for f in inspect.getouterframes(inspect.currentframe()): 
      args, _,_, local_dict = inspect.getargvalues(f[0]) 
      if args: 
       first_arg = args[0] 
       first_value = local_dict[first_arg] 
       print(type(first_value).__name__)