2012-05-24 21 views
7

即時當前模塊是「top level scripting environment__main__,我試圖確定一個函數的實際當前模塊(如果從其他地方導入)。Python:確定實際當前模塊(而不是__main__)

這可能聽起來像一個奇怪的事情,但背景是,我需要序列化一個函數,並在不同的機器上反序列化它(包括參數),爲此我需要確保正確的模塊AND NOT __main__在反序列化之前被導入(否則我會收到錯誤,說AttributeError: 'module' object has no attribute my_fun)。

到目前爲止,我已經試過inspection

import inspect 
print inspect.getmodule(my_fun) 

這給了我

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

。我也嘗試用globals()找到一些有用的東西,沒有運氣。

我真正想要的是<module 'example' from 'example.py'>。我想一個哈克的方式將使用什麼文件名解析它像

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

,然後按名稱查找sys.modules[m_name]模塊。

有沒有更清潔/更好的方法來做到這一點?

編輯: 瞭解IPython中的「FakeModule」和多一點的谷歌搜索後,我來到翻過this post,它描述正是我所面對,包括我目前的解決方案,它(這是明確導入當前模塊的問題import current_module和序列化current_module.my_fun而不是my_fun)。我試圖避免這種情況,因爲它可能對我的軟件包用戶來說並不直觀。

+0

你以前看過'nose'庫的內部,特別是'importer'模塊嗎? 「鼻子」做了一些非常相似的東西,所以它可能是一個尋找靈感的好地方。 –

回答

3

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

我使用的是什麼:

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

這是有效地與您的 「黑客」。老實說,我認爲它是最好的解決方案。

+0

謝謝溫斯頓,這是我一起去的解決方案,我從未遇到過任何討厭的問題。 – soramimo

+0

如果你在一個文件夾內運行你的腳本,例如「bar/foo.py」 – jwayne

+0

@jwayne,這不起作用,它會產生什麼? –

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 

同樣,這可能會或可能不會是「理想」的方式,但它運作良好,而據我所知並不意味着在大多數任何不良的權衡案例。希望這可以幫助。

3

我認爲你的原始解決方案是最好和最簡單的。如果你擔心它對你的用戶來說似乎違反直覺,那麼把它包裝在一個很好的函數中並記錄它的用途。

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

3

我知道這已經過時了,但是我在Python3中發現了一個更簡單的解決方案,它對我很有幫助。長話短說,還有對象的__spec__,它也存儲了實際的模塊名稱,而不是「__main__」。

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

這隻適用於模塊運行(帶'python -m'),否則'__spec__'爲'None'。但是這對我來說足夠了! (另外,對於我的用例,我可以跳過'inspect'並簡單地使用'import __main__; print(__ main __.__ spec __。name)')。 –

相關問題