有没有办法以编程方式找到定义函数的框架?我正在寻找像这样的函数get_defining_frame
的东西:
def foo():
def bar():
pass
return bar
bar = foo()
get_defining_frame(foo) # should be the same as inspect.currentframe()
get_defining_frame(bar) # should be the frame created by the call to foo
谢谢!
答案 0 :(得分:0)
每次调用函数时都会创建/删除帧。所以当你打电话时:
get_defining_frame(bar)
在您的示例代码中,创建bar
的框架已经消失。
函数对象不会对它们所定义的帧进行引用。这是一件好事,因为它会使所有其他局部变量不被释放。
你为什么需要这个?
答案 1 :(得分:0)
你不能得到这种信息,除非你自己存储(也许是装饰者)。
看看bar.__code__
和bar.__closure__
,也许他们会为您提供足够的信息。
__closure__
不会存储创建bar时的整个上下文,只会存储bar引用的变量,以节省内存效率。
应该做的伎俩:
def save_frame(func):
frame=inspect.currentframe().f_back
func.__frame = frame
return func
请记住,使用它会真正搞乱垃圾收集,存储整个堆栈帧意味着堆栈中任何地方都没有任何引用可以进行GC编辑(这就是为什么__closure__
只捕获引用的内容)。
答案 2 :(得分:0)
这是我在另一个主题上发布的答案的摘录,但发现它非常适用于该问题。它会向上移动框架以定位定义功能或应该在其中定义功能的位置。
下面的代码旨在查找是否已在类,模块或__main__
中定义了函数。在返回找到的内容之前,它已经找到了声明该函数的对象的本地字典。因此可以对其进行修改以返回本地语言字典或框架。
解决的问题是在将函数绑定到类之前,如何在类声明期间找到函数的作用域。因此o.__self__
或其他属性尚未分配。这是装饰器实现的一部分。
这适用于Python 3,但不适用于2。
>>> def _find_scope(func):
... try:
... owner_qname = '.'.join(func.__qualname__.split('.')[:-1])
... if len(owner_qname) == 0:
... module = sys.modules['__main__']
... if hasattr(module, func.__name__):
... return module.__dict__
... else:
... return None
... i = 0
... while True:
... f_locals = sys._getframe(i).f_locals
... i += 1
... if ('__qualname__' in f_locals and
... f_locals['__qualname__'] == owner_qname):
... if func.__name__ in f_locals:
... return f_locals
... else:
... return None
... except ValueError:
... return None