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

时间:2012-05-24 22:23:09

标签: python python-module inspection

我正在尝试确定函数的实际当前模块(如果从其他地方导入,则会看到),即使当前模块是“top level scripting environment__main__

这可能听起来像一个奇怪的事情,但背景是我需要序列化一个函数并在另一台机器上反序列化它(包括参数),为此我需要确保正确的模块AND NOT {{在反序列化之前导入1}}(否则我收到错误__main__)。

到目前为止,我已经尝试了inspection

AttributeError: 'module' object has no attribute my_fun

给了我

import inspect
print inspect.getmodule(my_fun)

当然。我也尝试使用<module '__main__' from 'example.py'> 找到有用的东西,没有运气。

我真正想要的是globals()。我想一个hacky方法是使用像

之类的东西从文件名中解析它
<module 'example' from 'example.py'>

然后按名称m_name = __main__.__file__.split("/")[-1].replace(".pyc","") 找到模块。

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

编辑: 在了解了ipython的“FakeModule”以及更多谷歌搜索之后,我来到this post,它描述了我正面临的问题,包括我当前的解决方案(明确导入当前模块{{1}并序列化sys.modules[m_name]而不是my_fun)。我试图避免这种情况,因为对我的软件包用户来说可能不太直观。

6 个答案:

答案 0 :(得分:7)

我知道这已经过时但我在Python3中找到了一个更简单的解决方案,对我有用。简而言之,对象的__spec__也存储了实际的模块名称,而不是&#34; __ main __&#34;。

import inspect
if obj.__class_.__module__ == "__main__":
    print(inspect.getmodule(obj).__spec__.name)

答案 1 :(得分:6)

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

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

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

答案 2 :(得分:6)

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

我使用的是:

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

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

答案 3 :(得分:2)

你可以做到这一点的一种方法 - 可能不是最好的方式,但它适用于我 - 是用__import__导入你的模块,并以类似下面的方式使用getattr

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

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

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

答案 4 :(得分: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

答案 5 :(得分:-1)

从 python 3.4 开始,

importlib.util.find_spec('__main__').name