我正在尝试确定函数的实际当前模块(如果从其他地方导入,则会看到),即使当前模块是“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)。我试图避免这种情况,因为对我的软件包用户来说可能不太直观。
答案 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