簡體   English   中英

從包的__init__.py中屏蔽python子模塊

[英]Mask a python submodule from its package's __init__.py

簡潔版本

一個特定的設置要求我在__init__.py中創建局部變量,該局部變量應屏蔽同一軟件包中的模塊。

例如,變量y (在__init__.py的本地上下文中)將隱藏模塊y.py import xy語句應產生局部變量,而不是加載模塊。

如果您不想閱讀有關特定設置的信息,請向下滾動至該問題; 沒有細節是可以理解的。

詳細說明

我已經實現了一組Python 2.7軟件包,每個軟件包都可能需要單獨的配置設置。 為了方便起見,我計划為每個程序包提供配置默認值,任何使用其中一個程序包的人都可以在本地覆蓋它們。

(這樣做的理由是在將應用程序部署到運行特定環境的機器(服務器,工作站,筆記本電腦等)時分發默認設置,但同時允許覆蓋配置而不會弄亂本地存儲庫或重置本地對代碼更新的適應。)

目錄結構示例為:

~/pkg/
  |
  +- package_a/
  |    |
  |    +- __init__.py
  |    +- mod_x.py
  |    +- mod_y.py
  |
  +- package_b/
  |    |
  |    +- __init__.py
  |    +- mod_z.py
  |
  +- config/
  |    |
  |    +- __init__.py
  |    +- package_a.py # Should locally override <pkg>_sample.py
  |    +- package_a_sample.py
  |    +- package_b_sample.py
  |
  +- test_this.py

我想訪問存儲在config/下的設置,例如常規模塊導入,例如:

# ~/pkg/test_this.py
import config.package_a as cfg_a

...但如果存在,則隱式切換到覆蓋文件。

我的解決方法

為了使流程自動化,我動態創建了指向正確配置文件導入的局部變量。 使用imp包,我可以導入一個模塊,並同時專門命名它。 (即在運行時,您無法區分是加載了<pkg>_sample.py還是<pkg>.py來提供配置。)

我終於結束了:

# ~/pkg/config/__init__.py
import os
import imp

__all__ = ['datastore']
_cfgbase = os.path.dirname(os.path.realpath(__file__))

for cfgmodule in __all__:
    if os.path.isfile(os.path.join(_cfgbase, cfgmodule + '.py')):
        locals()[cfgmodule] = imp.load_source(
            cfgmodule, os.path.join(_cfgbase, cfgmodule + '.py'))
    else:
        locals()[cfgmodule] = imp.load_source(
            cfgmodule, os.path.join(_cfgbase, cfgmodule + '_sample.py'))

實際上,這將創建對所需源文件的本地引用(當config/存在<pkg>.py時,省略<pkg>_sample.py

如果from config import package_a as cfg_a使用,我可以在其他模塊/腳本中使用它。

問題

本質上,這個問題可以歸結為眾所周知的import xy vs from x import y -thing。

但是這里有所不同。

我知道import xy要求y是一個模塊。 是否有可能將模塊隱藏在其包的__init__.py在導入時提供局部變量instad?

  • from x import yx__init__.py產生局部變量y
  • 即使__init__.py存在局部變量yimport xy 始終會導入模塊。

我不能強迫每個人都始終使用前一個import語句,人們喜歡在其代碼中使用后一個import語句。

有什么建議嗎?

編輯:固定標題。 抱歉。

解決方案

感謝@ martijn-pieters指出sys.modules

實際上,如果沒有正確命名新導入,我的方法就無需將新導入顯式添加到sys.modules即可完美地工作:

locals()[cfgmodule] j= imp.load_source(
    'config.' + cfgmodule, os.path.join(_cfgbase, cfgmodule + '.py'))

這樣就解決了這個問題,因為它沒有使用標准名稱(這里為package_a )注冊新的子模塊,而是將其注冊為我的config包的子模塊。

非常感謝!

import xy並不需要y作為模塊。 import xysys.modules結構中查找'x''x.y'鍵。 如果兩者都找到,則x綁定到sys.modules['x'] 只有當'x.y'不存在時,Python才會尋找要加載的模塊。

然后,訣竅是將y塞入sys.modules

sys.modules['x.y'] = y

暫無
暫無

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

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