簡體   English   中英

Python:確定實際的當前模塊(不是 __main__)

[英]Python: determine actual current module (not __main__)

我正在嘗試確定函數的實際當前模塊(如從其他地方導入時所看到的),即使當前模塊是“頂級腳本環境__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而不是 my_fun)。 我試圖避免這種情況,因為它可能對我的包的用戶不直觀。

我實際上遇到了同樣的問題。

我用的是:

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

這實際上與您的“黑客”相同。 老實說,我認為這是最好的解決方案。

我知道這已經過時了,但我在 Python3 中找到了一個對我有用的更簡單的解決方案。 長話短說,對象的 __spec__ 也存儲了實際的模塊名稱,而不是“__main__”。

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

編輯:回想起來,到目前為止,最好和最干凈的解決方案是首先避免陷入這種情況; 如果正在序列化的是您的代碼,請將所有可序列化的函數移動到由主程序腳本加載的模塊中。 這使得在任何和所有情況下都可以檢索函數的來源,而無需任何黑客或特殊情況。

如果這是不可能的,我認為您的原始解決方案(從__main__.__file__檢索模塊名稱)是最好和最簡單的。 如果您擔心它對您的用戶來說似乎違反直覺,請將其包裝在一個不錯的函數中並記錄它的用途。

當您將模塊作為__main__運行時,python 確實不會將其與其正常的模塊名稱相關聯:如果您import example ,它將第二次加載文件,就好像它是一個單獨的模塊一樣。 事實上,這可能發生在您的情況,否則您將無法在sys.modules按名稱找到您的模塊:模塊example和模塊__main__確實是單獨的運行時對象,因為您會發現是否顯式更改模塊其中之一的變量。

您可以執行此操作的一種方法 - 可能不是最好的方法,但對我__import__ - 是使用__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

同樣,這可能是也可能不是“理想”的方式,但它運作良好,據我所知,在大多數情況下不會帶來任何不利的權衡。 希望這可以幫助。

我認為現有的任何答案都沒有直接回答這個問題:當模塊作為__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

從python 3.4開始,

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM