是否可以从帧对象中检索任何类信息?我知道如何获取文件(frame.f_code.co_filename),函数(frame.f_code.co_name)和行号(frame.f_lineno),但希望能够获取活动对象的类的名称框架的实例(如果不在实例中,则为None)。
答案 0 :(得分:18)
我不相信,在帧对象级别,有任何方法可以找到已调用的实际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
参数,而是使用描述符实现。根据您想要做什么,您可能需要花些时间深入挖掘并找到所有这些问题的解决方法(您可以检查返回类中存在的框架函数并共享相同的源,检测描述符调用是可能的,同样的类方法等。)
答案 1 :(得分: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
答案 2 :(得分:3)
我遇到同样的问题时,我刚看到这篇文章。然而,由于已列出的所有原因,我并不认为“自我”方法是可接受的解决方案。
以下代码演示了一种不同的方法:给定一个框架对象,它在全局视图中搜索具有匹配成员名称和代码块的对象。搜索并不详尽,因此有可能不会发现所有类,但找到的类应该是我们要查找的类,因为我们验证了匹配代码。
代码的对象是在函数名前加上其类名,如果找到的话:
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__
或更深,则可以避免全局搜索,因此肯定有优化/杂交的空间。
答案 3 :(得分: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__)
答案 4 :(得分: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;
它的工作方式其实很简单,我们检查一下
如果 Nº4 为真,那么我们知道 cls
是一个类,其中包含一些方法 member
,其代码与我们从框架中获得的代码相同。
一切都很好,但这并不完美。就我测试过的而言,它不适用于属性修饰的方法,而且我还不确定如何处理这种极端情况。但它在常规和静态方法上对我有用,这正是我目前所需要的,所以很公平。
但是请注意,这非常很慢,尽管我认为这是不言而喻的。根据我自己的基准测试,每 100,000 次调用通常需要大约 2 到近 3 秒。这对于我当前的用例来说是可以接受的,但是如果您需要一次多次使用它,您可能需要先进行一些优化。我会把它交给你能干的人 (:
希望搜索引擎在这里遇到的其他人能找到一些有用的东西。
干杯。