从栈帧中获取模块对象

13 投票
2 回答
4510 浏览
提问于 2025-04-15 17:37

给定一个帧对象,我需要获取对应的模块对象。换句话说,就是要实现一个叫做callers_module的功能,让下面的代码可以正常工作:

import sys
from some_other_module import callers_module
assert sys.modules[__name__] is callers_module()

这样做是合理的,因为我可以在这个函数中生成一个调用栈的跟踪信息来测试这个案例。引入的模块只是为了让这个例子完整且可以测试,同时也防止callers_module使用__name__这个快捷方式,因为它在不同的模块中。

我尝试过这个:

import inspect
def callers_module():
  return inspect.currentframe().f_back

这个方法获取了一个帧对象,利用f_code可以得到一个代码对象,但我找不到办法获取对应的模块或它的名字(以便与sys.modules一起使用)。如果我能获取到函数对象,那些对象有一个__module__属性(同时也有代码对象),但帧对象中没有这个属性。实际上,并不是所有的代码对象都属于函数对象,比如我测试案例中的代码(上面提到的assert)。同样,帧对象或代码对象也不一定有模块,但很多都有,而在我的情况下它们会有,所以这部分不需要特别处理;不过,如果没有的话,返回None或者抛出异常也是可以的。

我感觉我可能漏掉了什么简单的东西。要让这个功能正常工作,需要做些什么呢?

2 个回答

15

虽然inspect.getmodule这个方法很好用,我之前确实找错了地方,但我找到了一种对我来说稍微更好的解决方案:

def callers_module():
  module_name = inspect.currentframe().f_back.f_globals["__name__"]
  return sys.modules[module_name]

这个方法仍然使用inspect.currentframe(我更喜欢这个,因为它比sys._getframe更好),但它没有调用inspect.getmodule中的模块和文件名的映射。

另外,这个问题让我想到了一个有趣的方法来管理__all__

from export import export

@export
class Example: pass

@export
def example: pass

answer = 42
export.name("answer")

assert __all__ == ["Example", "example", "answer"]
7

在编程中,有时候我们会遇到一些问题,特别是在使用某些工具或库的时候。这些问题可能会让我们感到困惑,尤其是当我们不太了解这些工具的工作原理时。比如,有些人可能会在使用某个函数时,发现它的表现和他们预期的不一样。这种情况通常需要我们仔细检查代码,看看是不是哪里出错了,或者是对这个函数的理解有误。

在这种情况下,查看文档是个好主意。文档通常会详细说明这个函数的用法、参数以及返回值等信息。通过阅读文档,我们可以更好地理解这个工具是如何工作的,从而避免一些常见的错误。

另外,向社区求助也是一个不错的选择。像StackOverflow这样的平台上,有很多经验丰富的程序员,他们可能遇到过类似的问题,并且愿意分享他们的解决方案。通过提问或者搜索相关问题,我们可以找到很多有用的建议和解决办法。

总之,遇到问题时,不要慌张。先检查代码,再查阅文档,最后可以向社区寻求帮助。这样一步一步来,问题通常都能得到解决。

import inspect
def callers_module():
   module = inspect.getmodule(inspect.currentframe().f_back)
   return module

撰写回答