代码之家  ›  专栏  ›  技术社区  ›  Roger Pate

从堆栈帧检索模块对象

  •  8
  • Roger Pate  · 技术社区  · 16 年前

    给定一个框架对象,我需要得到相应的模块对象。换句话说,实现调用者的模块,这样就可以:

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

    (这是等效的,因为我可以在函数中为这个测试用例生成一个堆栈跟踪。导入只是为了使该示例完整且可测试,并防止呼叫者模块使用“名称”的快捷方式,因为它位于不同的模块中。)

    我尝试过:

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

    它得到一个框架对象,在这个框架对象上,F代码将给我一个代码对象,但我不知道如何得到相应的模块或其名称(用于sys.modules)。如果我能得到函数对象,它们有一个模块属性(也有代码对象),但框架中没有。实际上,并不是所有的代码对象都属于函数对象,比如我的测试用例的代码(上面有assert)。对于没有模块的框架/代码对象也可以这样说,但它们中的许多都有,在我的例子中,它们会有,所以不需要处理;但是,在这种情况下,一个简单的无或异常也是可以的。

    我好像错过了一些简单的东西。需要做什么才能起作用?

    2 回复  |  直到 16 年前
        1
  •  2
  •   manifest    16 年前
    import inspect
    def callers_module():
       module = inspect.getmodule(inspect.currentframe().f_back)
       return module
    
        2
  •  6
  •   Roger Pate    16 年前

    虽然inspect.getmodule工作得很好,而且我确实在错误的地方找到了它,但我找到了一个更好的解决方案:

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

    它仍然使用inspect.currentframe(我更喜欢使用完全相同的sys.getframe),但不调用inspect的模块文件名映射(在inspect.getmodule中)。

    此外,这个问题激发了一种有趣的方法 manage __all__ :

    from export import export
    
    @export
    class Example: pass
    
    @export
    def example: pass
    
    answer = 42
    export.name("answer")
    
    assert __all__ == ["Example", "example", "answer"]