Python:如何从“框架”对象中检索类信息?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2203424/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python: How to retrieve class information from a 'frame' object?
提问by Kevin Little
Is it possible to retrieve any class information from a frame object? I know how to get the file (frame.f_code.co_filename), function (frame.f_code.co_name) and line number (frame.f_lineno), but would like to be able to also get the name of the class of the active object instance of the frame (or None if not in an instance).
是否可以从框架对象中检索任何类信息?我知道如何获取文件 (frame.f_code.co_filename)、函数 (frame.f_code.co_name) 和行号 (frame.f_lineno),但希望也能够获取活动对象的类名框架的实例(如果不在实例中,则为 None )。
回答by Clément
I don't believe that, at the frame object level, there's any way to find the actual python function object that has been called.
我不相信,在框架对象级别,有任何方法可以找到已被调用的实际 python 函数对象。
However, if your code rely on the common convention : naming the instance parameter of a method self
, then you could do the following :
但是,如果您的代码依赖于通用约定:命名方法的实例参数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
If you don't want to use getargvalues
, you can use directly frame.f_locals
instead of value_dict
and frame.f_code.co_varnames[:frame.f_code.co_argcount]
instead of args
.
如果不想使用getargvalues
,可以直接使用frame.f_locals
代替value_dict
和frame.f_code.co_varnames[:frame.f_code.co_argcount]
代替args
。
Keep in mind that this is still only relying on convention, so it is not portable, and error-prone:
请记住,这仍然仅依赖于约定,因此它不可移植,并且容易出错:
- if a non-method function use
self
as first parameter name, thenget_class_from_frame
will wrongly return the class of the first parameter. - it can be misleading when working with descriptors (it will return the class of the descriptor, not of the actual instance being accessed).
@classmethod
and@staticmethod
won't take aself
parameter and are implemented with descriptors.- and surely a lot more
- 如果非方法函数
self
用作第一个参数名称,get_class_from_frame
则将错误地返回第一个参数的类。 - 使用描述符时可能会产生误导(它将返回描述符的类,而不是正在访问的实际实例的类)。
@classmethod
并且@staticmethod
不会接受self
参数并使用描述符实现。- 当然还有更多
Depending on what exactly you want to do, you might want to take some time to dig deeper and find workarounds for all these issues (you could check the frame function exist in the returned class and share the same source, detecting descriptor calls is possible, same for class methods, etc..)
根据您究竟想要做什么,您可能需要花一些时间深入挖掘并找到所有这些问题的解决方法(您可以检查返回的类中是否存在 frame 函数并共享相同的源,检测描述符调用是可能的,类方法等也一样。)
回答by Ruslan
This is a bit shorter, but does about the same. Returns None if class name not available.
这有点短,但大致相同。如果类名不可用,则返回 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
回答by gertjan
I just came across this post as I was faced with the same problem. I did not consider the 'self' method an acceptable solution, however, for all the reasons already listed.
我刚刚遇到了这篇文章,因为我遇到了同样的问题。然而,出于已经列出的所有原因,我并不认为“自我”方法是一个可接受的解决方案。
The following code demonstrates a different approach: given a frame object it searches the globals for an object with matching member name and code block. The search is hardly exhaustive so it is possible that not all classes will be uncovered, but what classes are found should be the ones we are looking for because we verify matching codes.
下面的代码演示了一种不同的方法:给定一个框架对象,它在全局变量中搜索具有匹配成员名称和代码块的对象。搜索并不详尽,因此可能不会发现所有类,但找到的类应该是我们正在寻找的类,因为我们会验证匹配代码。
Object of the code is to prepend a function name with its class name, if found:
代码的目标是在函数名前面加上它的类名,如果找到的话:
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
Note the use of __dict__
instead of getattr
to prevent catching of derived classes.
请注意使用__dict__
代替getattr
来防止捕获派生类。
Note further that a global search can be avoided if self = frame.f_locals['self']; obj = self.__class__
gives a match, or any obj in self.__class__.__bases__
or deeper, so there is certainly room for optimization / hybridization.
进一步注意,如果self = frame.f_locals['self']; obj = self.__class__
给出匹配或任何obj in self.__class__.__bases__
或更深的匹配,则可以避免全局搜索,因此肯定有优化/混合的空间。
回答by gerardw
If a method is a class method, the class will be the first argument. This prints out the type of the first arg if present for each calling stack frame:
如果方法是类方法,则该类将是第一个参数。这将打印出每个调用堆栈帧的第一个 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__)