Python:如何从';框架';对象

Python:如何从';框架';对象,python,introspection,Python,Introspection,是否可以从框架对象检索任何类信息?我知道如何获取文件(frame.f_code.co_filename)、函数(frame.f_code.co_name)和行号(frame.f_lineno),但我也希望能够获取帧的活动对象实例的类的名称(如果不在实例中,则无)。我不相信,在帧对象级别,有任何方法可以找到已调用的实际python函数对象 但是,如果您的代码依赖于通用约定:命名方法的实例参数self,则可以执行以下操作: def get_class_from_frame(fr): import

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

我不相信,在帧对象级别,有任何方法可以找到已调用的实际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
如果不想使用,可以直接使用
frame.f\u locals
而不是
value\u dict
frame.f\u code.co\u varnames[:frame.f\u code.co\u argcount]
而不是
args

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

  • 如果非方法函数使用
    self
    作为第一个参数名,则
    get\u class\u from\u 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
注意使用
\uuu dict\uuu
而不是
getattr
来防止捕获派生类


进一步注意,如果
self=frame.f_locals['self'],则可以避免全局搜索;obj=self.\uuuu class\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。这将打印出每个调用堆栈帧的第一个参数(如果存在)的类型:

    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__) 

你好,原谅necro;但这些对我来说都不管用,因为这里的一些片段激发了我的灵感,我想出了另一个选择。这就是我在python 3.7中为类方法所做的工作:

进口检验;
def QLNAME(帧):
代码=frame.f_代码;
名称=code.co\u名称;
qual=无;
对于中的cls(对于frame.f_globals.values()中的obj,针对obj)#
如果检查isclass(obj)):
如果hasattr(cls,名称):
成员=getattr(cls,名称);
如果未检查。isfunction(成员):继续;
如果成员.\uuuu代码\uuuu==代码:
qual=成员;
打破
返回质量;
我们检查,它的工作方式实际上非常简单

  • 对于框架全局范围内的类
  • 如果该类有一个成员共享有问题的名称
  • 此成员是否为函数
  • 最后,比较两个函数的代码
  • 如果Nº4为真,那么我们就知道
    cls
    是一个类,它有一些方法
    member
    ,其代码与我们从框架中得到的代码相同

    一切都很好,但这并不完美。就我所测试的而言,它对属性修饰的方法不起作用,而且我还不能完全确定如何处理这种情况。但它在常规和静态的方法上对我有效,这是我目前所需要的一切,非常公平

    但请注意,这是非常缓慢的,尽管我认为这是不言而喻的。根据我自己的基准测试,每100000次呼叫通常需要2到3秒左右的时间。这对于我当前的用例来说是可以接受的,但是如果您需要一次性使用它超过几次,那么您可能需要首先进行一些优化。我将把它交给你的能手(:

    希望在这里搜索引擎遇到问题的其他人能找到一些有用的东西


    干杯。

    谢谢你的回答,Clément;它很详细,考虑周到。我仍然希望得到不止一个回答!但如果没有,这一个就足够了…好吧,等待足够长的时间。这是一个好的回答!我本来希望框架结构提供更好的支持,但事实就是如此。再次感谢Clément!要在列表中添加一个,请注意,“self”可能是派生类的实例,而我们可能不感兴趣。回答得好!更好的是,您可以使用
    f.f_locals['''u______'].\uuu name\uuuuu
    ,这也应该包括
    @classmethod
    @staticmethod
    案例。@LucioPaiva不起作用。在f\u locals中没有键
    “\uuuu class\uuuuuuuuuu'