[英]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.