[英]python import the same file name programatically from different folders
[英]python import path: packages with the same name in different folders
我正在為幾個客戶同時開發幾個Python項目。 我的項目文件夾結構的簡化版本如下所示:
/path/
to/
projects/
cust1/
proj1/
pack1/
__init__.py
mod1.py
proj2/
pack2/
__init__.py
mod2.py
cust2/
proj3/
pack3/
__init__.py
mod3.py
當我例如希望從使用功能proj1
,我延伸sys.path
通過/path/to/projects/cust1/proj1
(例如通過設置PYTHONPATH
或添加.pth
文件到site_packages
文件夾或甚至修改sys.path
直接地)然后像這樣導入模塊:
>>> from pack1.mod1 import something
當我處理更多項目時,不同的項目具有相同的包名稱:
/path/
to/
projects/
cust3/
proj4/
pack1/ <-- same package name as in cust1/proj1 above
__init__.py
mod4.py
如果我現在只是通過/path/to/projects/cust3/proj4
將sys.path
擴展/path/to/projects/cust3/proj4
,我仍然可以從proj1
導入,但不能從proj4
:
>>> from pack1.mod1 import something
>>> from pack1.mod4 import something_else
ImportError: No module named mod4
我認為第二次導入失敗的原因是Python只搜索sys.path
中找到pack1
包的第一個文件夾,如果沒有找到mod4
模塊,則mod4
。 我在之前的一個問題中已經問過這個問題,請參閱具有相同名稱的import python模塊 ,但內部細節仍然不清楚。
無論如何,顯而易見的解決方案是通過將項目目錄轉換為超級包來添加另一層命名空間限定:將__init__.py
文件添加到每個proj*
文件夾,並從擴展sys.path
的行中刪除這些文件夾,例如
$ export PYTHONPATH=/path/to/projects/cust1:/path/to/projects/cust3
$ touch /path/to/projects/cust1/proj1/__init__.py
$ touch /path/to/projects/cust3/proj4/__init__.py
$ python
>>> from proj1.pack1.mod1 import something
>>> from proj4.pack1.mod4 import something_else
現在我遇到了不同客戶的不同項目具有相同名稱的情況,例如
/path/
to/
projects/
cust3/
proj1/ <-- same project name as for cust1 above
__init__.py
pack4/
__init__.py
mod4.py
由於與以前相同的原因,嘗試從mod4
導入不再起作用了:
>>> from proj1.pack4.mod4 import yet_something_else
ImportError: No module named pack4.mod4
按照之前解決此問題的相同方法,我將添加另一個包/命名空間層並將客戶文件夾轉換為超級超級包。
但是,這與我對項目文件夾結構的其他要求相沖突,例如
對某些項目文件夾的簡化,更真實的描述如下所示:
/path/
to/
projects/
cust1/
proj1/
Development/
code/
javascript/
...
python/
pack1/
__init__.py
mod1.py
doc/
...
Release/
...
proj2/
Development/
code/
python/
pack2/
__init__.py
mod2.py
我不知道如何滿足python解釋器對文件夾結構的要求以及我同時擁有的要求。 也許我可以使用一些符號鏈接創建一個額外的文件夾結構並在sys.path
使用它,但是看看我已經做出的努力,我感覺我的整個方法存在根本性的錯誤。 在旁注中,我也很難相信python確實限制了我選擇的源代碼文件夾名稱,因為它似乎在描述的情況下。
如何設置我的項目文件夾和sys.path
以便如果項目和包具有相同的名稱,我可以以一致的方式從所有項目導入?
這是我的問題的解決方案,雖然起初可能並不明顯。
在我的項目中,我現在已經為每個客戶引入了一個命名空間的約定。 在每個客戶文件夾( cust1
, cust2
等)中,都有一個帶有以下代碼的__init__.py
文件:
import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
我的包中的所有其他__init__.py
文件都是空的(主要是因為我還沒有時間去了解它們還有什么用)。
正如這里所解釋的, extend_path
確保Python知道包中有多個子包,物理上位於其他地方 - 從我的理解 - 然后解釋器在第一個包下找不到模塊后就不會停止搜索它在sys.path
遇到的路徑,但搜索__path__
所有路徑。
我現在可以以一致的方式訪問所有項目之間的所有代碼,例如
from cust1.proj1.pack1.mod1 import something
from cust3.proj4.pack1.mod4 import something_else
from cust3.proj1.pack4.mod4 import yet_something_else
在缺點方面,我不得不創建一個更深入的項目文件夾結構:
/path/
to/
projects/
cust1/
proj1/
Development/
code/
python/
cust1/
__init__.py <--- contains code as described above
proj1/
__init__.py <--- empty
pack1/
__init__.py <--- empty
mod1.py
但這對我來說似乎是非常可以接受的,特別是考慮到我需要付出很少的努力來維持這個慣例。 sys.path
由/path/to/projects/cust1/proj1/Development/code/python
擴展為該項目。
在旁注中,我注意到同一客戶的所有__init__.py
文件中,在sys.path
中首先出現的路徑中的那個文件被執行,無論我從哪個項目導入東西。
你應該使用優秀的virtualenv和virtualenvwrapper工具。
如果您不小心從另一個客戶/項目中導入代碼並且沒有注意到會發生什么? 當你交付它幾乎肯定會失敗。 我會采用一次為一個項目設置PYTHONPATH的約定,而不是試圖讓你曾經寫過的所有內容都可以立即導入。
您可以使用每個項目的包裝器腳本來設置PYTHONPATH並啟動python,或者在切換項目時使用腳本來切換環境。
當然,有些項目依賴於其他項目(您提到的那些庫),但如果您打算讓客戶能夠同時導入多個項目,那么您必須安排名稱不要沖突。 當您在PYTHONPATH上有多個不應該一起使用的項目時,您只能遇到此問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.