2014-07-18 25 views
0

我有以下目錄結構:如何使`from。進口utils`工作

some-tools-dir/ 
    base_utils.py 
    other_utils.py 
    some-tool.py 
    some-other-tool.py 

some-other-tools-dir/ 
    basetools -> symlink to ../some-tools-dir 
    yet-another-tool.py 

other_utils.py,我有:

import base_utils 

現在,在yet-another-tool.py,我想做的事:

import basetools.other_utils 

這是行不通的,因爲Python不會將basetools識別爲Python包。 因此我添加一個空的basetools/__init__.py。 現在,在other_utils,我得到異常:

import base_utils 
ImportError: No module named base_utils 

所以我改變該行:

from . import base_utils 

而且yet-another-tool.py作品現在。

但是,some-tool.py不起作用了。它進口other_utils,在那裏我得到異常:

from . import base_utils 
ValueError: Attempted relative import in non-package 

現在,我可以在這個黑客/解決方法添加到some-tools-dir/*-tool.py

import os, sys 
__package__ = os.path.basename(os.path.dirname(os.path.abspath(__file__))) 
sys.path += [os.path.dirname(os.path.dirname(os.path.abspath(__file__)))] 
__import__(__package__) 

,另外,使相對在這些文件中的所有當地的進口。

解決了這個問題,我想。但是,它看起來有點非常難看,我必須修改sys.path。我嘗試了幾種變種,但是,如果可能的話,我想支持多個Python版本,因此使用模塊importlib變得複雜,尤其是,因爲我有Python 3.2,而且我不喜歡使用模塊imp,因爲它已被棄用。而且,它似乎只是變得更加複雜。

有什麼我失蹤了嗎?這對於一個似乎並不罕見的用例來說,看起來都很醜陋,對於我來說太複雜了。我的黑客有更簡潔的版本嗎?

我願意做的一個限制是只支持Python> = 3.2,如果這可以簡化任何事情。

回答

1

(請注意,這個答案是由來自this answerthis question拼湊的信息製作的,所以上去,投票支持他們,如果你喜歡它)

這看起來少了幾分哈克,並與Python至少工作2.7+:

if __name__ == "__main__" and __package__ is None: 
    import sys, os.path as path 
    sys.path.append(path.dirname(path.dirname(path.abspath(__file__)))) 

from some_tools_dir import other_utils 

我認爲你發現這個困難的主要原因是因爲在python包內部有可執行腳本實際上是不尋常的。 Guido van Rossum實際上稱它爲"antipattern"。通常情況下你的可執行生活在包的根目錄之上,然後可以簡單地使用:

from some_tools_dir import other_utils 

沒有任何大驚小怪。

或者,如果你想要執行的是住在包的腳本,你居然(同樣,從封裝的父目錄),把它作爲包裝的一部分:

python -m some_tools_dir.other_utils 
+0

請注意,我在我的問題中使用了帶「 - 」的目錄名,因爲我想要一個通用的解決方案。您的解決方案假定它是一個有效的軟件包名稱('some_tools_dir')。 ---但是,我決定重組我的文件並遵循Guidos的建議。另外,'python -m'不是一個真正的解決方案,因爲我希望能夠使腳本可執行,並且我不知道如何通過hashbang來完成。 – Albert

0

您是否可以將頂級根路徑添加到PYTHONPATH中?

如果是的話,可以再加入

__init__.py 

文件到一些工具-DIR(和/或一些,其他工具-DIR)

從other_utils.py你做

然後

from some-tools-dir import base_utils 

而且在yet-another-tool.py你做

from some-tools-dir import other_utils 

然後,您可以刪除符號鏈接,並擁有適當的命名空間。

+0

我已經做到了。這是我在我的問題中寫的。此外,你的代碼不起作用,因爲模塊名稱不能包含'「 - 」'。 – Albert