16

我正在尝试确定函数的实际当前模块(如从其他地方导入的那样),即使当前模块是“顶级脚本环境__main__

这听起来像是一件奇怪的事情,但背景是我需要序列化一个函数并在另一台机器上反序列化它(包括参数),为此我需要确保__main__在反序列化之前导入正确的模块而不是(否则我会收到错误消息AttributeError: 'module' object has no attribute my_fun)。

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

import inspect
print inspect.getmodule(my_fun)

这给了我

<module '__main__' from 'example.py'>

当然。我还尝试使用 找到有用的东西globals(),但没有运气。

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

m_name = __main__.__file__.split("/")[-1].replace(".pyc","")

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

有没有更清洁/更好的方法来做到这一点?

编辑:在了解了 ipython 的“FakeModule”和更多的谷歌搜索之后,我看到了这篇文章,它准确地描述了我面临的问题,包括我当前的解决方案(显式导入当前模块import current_module并序列化current_module.my_fun而不是我的乐趣)。我试图避免这种情况,因为它对我的包的用户来说可能不直观。

4

6 回答 6

8

我实际上遇到了同样的问题。

我用的是:

return os.path.splitext(os.path.basename(__main__.__file__))[0]

这实际上与您的“黑客”相同。老实说,我认为这是最好的解决方案。

于 2012-09-05T17:41:30.313 回答
8

我知道这已经过时了,但我在 Python3 中找到了一个对我有用的更简单的解决方案。长话短说,对象的 __spec__ 也存储了实际的模块名称,而不是“__main__”。

import inspect
if obj.__class_.__module__ == "__main__":
    print(inspect.getmodule(obj).__spec__.name)
于 2015-04-30T15:33:46.297 回答
6

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

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

当您将模块运行为__main__时,python 确实不会将其与其正常的模块名称相关联:如果您import example是 ,它将再次加载文件,就好像它是一个单独的模块一样。实际上,这可能发生在您的情况下,否则您将无法在以下位置按名称找到您的模块sys.modules: Moduleexample和 module__main__确实是单独的运行时对象,因为您会发现是否在其中一个中显式更改了模块变量.

于 2012-07-13T22:50:30.690 回答
2

你可以做到这一点的一种方法——可能不是最好的方法,但它对我有用——是导入你的模块__import__getattr以如下方式使用。

(这里我使用了这篇文章中描述的关于动态加载模块的一些想法。)

def dynamic_import(name):
    mod = __import__(name)
    components = name.split('.')
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod

tmodule = dynamic_import('modA')
# Print the module name
print tmodule
# Use the module's contents
t = tmodule.myObject()
t.someMethod()

modA.py 看起来像这样:

class myObject():
    def someMethod(self):
        print "I am module A"

所以你可以看到我们得到了我们导入的模块的名称,并且仍然可以以正常的方式使用模块中的对象和方法。当我运行它时,我得到以下信息:

python experiment.py 
<module 'modA' from 'modA.pyc'>
I am module A

同样,这可能是也可能不是“理想”方式,但它运作良好,据我所知,在大多数情况下不会带来任何不良权衡。希望这可以帮助。

于 2012-05-25T15:04:51.560 回答
0

我认为任何现有的答案实际上都没有直接回答这个问题:当它运行时如何获得模块的名称__main__

在大多数步骤中使用检查...

import inspect

def module_name(obj):
    module_name = obj.__module__

    if "__main__" in module_name:
        # get parent modules of object
        mod_obj = inspect.getmodule(obj) # type: module

        # from the filename of the module, get its name
        mod_suffix  = inspect.getmodulename(inspect.getmodule(obj).__file__)

        # join parent to child with a .
        module_name = '.'.join([mod_obj.__package__, mod_suffix])

    return module_name
于 2020-12-08T08:47:30.737 回答
-1

从 python 3.4 开始,

importlib.util.find_spec('__main__').name
于 2021-05-05T14:17:48.287 回答