Python:确定实际的当前模块(不是__main__)

sor*_*imo 12 python python-module inspection

我正在尝试确定函数的实际当前模块(如果从其他地方导入,则会看到),即使当前模块是" 顶级脚本环境 " __main__.

这可能听起来像一个奇怪的事情,但背景是我需要序列化一个函数并在不同的机器上反序列化它(包括参数),为此我需要确保__main__在反序列化之前导入正确的模块AND NOT (否则我得到一个错误说AttributeError: 'module' object has no attribute my_fun).

到目前为止,我已经尝试过检查:

import inspect
print inspect.getmodule(my_fun)
Run Code Online (Sandbox Code Playgroud)

这给了我

<module '__main__' from 'example.py'>
Run Code Online (Sandbox Code Playgroud)

当然.我也试过找一些有用的东西globals(),没有运气.

我真正想要的是<module 'example' from 'example.py'>.我想一个hacky方法是使用类似的东西从文件名解析它

m_name = __main__.__file__.split("/")[-1].replace(".pyc","")
Run Code Online (Sandbox Code Playgroud)

然后按名称查找模块sys.modules[m_name].

有更干净/更好的方法吗?

编辑:在了解了ipython的"FakeModule"以及更多谷歌搜索后,我发现了这篇文章,它正好描述了我面临的问题,包括我当前的解决方案(明确导入当前模块import current_module并序列化current_module.my_fun而不是my_fun).我试图避免这种情况,因为对我的软件包的用户来说可能不太直观.

小智 7

我知道这已经过时但我发现Python3中的一个更简单的解决方案对我有用.简而言之,对象的__spec__也存储实际的模块名称而不是"__main__".

import inspect
if obj.__class_.__module__ == "__main__":
    print(inspect.getmodule(obj).__spec__.name)
Run Code Online (Sandbox Code Playgroud)

  • 这仅在作为模块运行时使用(使用`python -m`),否则`__spec__`是'None`.但这对我来说已经足够了!(另外,对于我的用例,我可以跳过`inspect`并简单地使用`import __main__; print(__ main __.__ spec __.name)`.) (2认同)

ale*_*xis 6

编辑:回想起来,到目前为止,最好和最干净的解决方案是避免首先出现这种情况; 如果它是您的序列化代码,请将所有可序列化函数移动到主程序脚本加载的模块.这使得函数的起源可以在任何和所有情况下检索,而不需要任何黑客或特殊情况.

如果那是不可能的,我认为您的原始解决方案(从中检索模块名称__main__.__file__)是最好和最简单的.如果您担心它对您的用户来说似乎是违反直觉的,请将其包装在一个很好的功能中并记录它的用途.

当你运行一个模块时__main__,python确实没有将它与它的正常模块名称相关联:如果你import example,它将第二次加载文件,就像它是一个单独的模块一样.事实上,这可能发生在您的情况下,否则您将无法通过名称找到您的模块sys.modules:模块example和模块__main__实际上是单独的运行时对象,因为您将发现是否明确更改其中一个模块变量.


Win*_*ert 6

我实际遇到了同样的问题.

我用的是:

return os.path.splitext(os.path.basename(__main__.__file__))[0]
Run Code Online (Sandbox Code Playgroud)

这实际上与你的"黑客"相同.老实说,我认为这是最好的解决方案.