2013-08-05 220 views
5

我在計算如何在Python中執行相對導入時遇到了一些麻煩。我目前正在研究我的第一個主要項目,所以我想用單元測試來做。但是,我遇到了我的文件結構和相關導入問題。Python中的相對導入混亂

這是我目前的結構:

App/ 
    __init__.py 
    src/ 
    __init__.py 
    person.py 
    tests/ 
    __init__.py 
    person_tests.py 

我想要做的是能夠導入到person.py爲person_tests.py單元測試。我曾嘗試以下:

from . import person 
from .. import person 
from .App.src import person 
from ..App.src import person 
from ..src.person import * 
from ..src import person 
from .src import person 

每上述之一拋出任何語法錯誤或

ValueError: Attempted relative import in non-package 

可有人請澄清這一點給我嗎?

編輯:Python版本是2.7。 編輯:我希望能夠用unittest或nose來使用它。

+1

我認爲在大多數情況下,絕對進口是首選方式。 [一些閱讀](http://www.python.org/dev/peps/pep-0328/#rationale-for-absolute-imports)(不要錯過之後關於相對導入的部分)。 – keyser

+0

您可以在「App」目錄中添加一個(可能)空的「__init __。py」文件,使其成爲一個包 –

+0

糟糕。我忘了提及我在App目錄中有一個'__init __。py'文件。更新問題。 – firstofth300

回答

-1

你可以將它追加到sys.path。

import sys 
sys.path.append("../src") 
import person 
+1

你能再詳細一點嗎? – horchler

+0

通過將目錄添加到Python路徑中,您告訴有一個新的目錄來搜索文件/模塊 –

+0

這會起作用,但這不是一個好主意。你傾向於以不同的名稱導入同一個模塊兩次(這意味着每個全局的兩個獨立副本等)。 [PEP 328](http://www.python.org/dev/peps/pep-0328/)解釋了原因。如果您必須這樣做,請將包的頂層追加到路徑中,然後絕對導入它。 – abarnert

4

我的猜測(如果我錯了,我會刪除它)是,您嘗試使用person_tests.py作爲頂層腳本,而不是作爲包內的模塊,方法如下:

$ cd App/tests 
$ python person_tests.py 

在這種情況下,person_tests不會最終成爲App.tests.person_tests,但只是__main__(或有少許變化,作爲頂級person_tests,其具有相同的基本問題)。因此,..並不是指App,因此無法以person作爲相對導入。

更一般地說,PYTHONPATH,包括.都不應該在任何軟件包目錄的中間,否則將會被破壞。

正確的答案是不這樣做。做這樣的事情:

$ python -m App.tests.person_tests 

或者編寫一個導入模塊的頂層(包外)腳本,並運行該頂層腳本。

+0

所以我想你是建議我寫自己的pythonic unittest跑步者。 – firstofth300

+0

@DaBungalow:一點都不。要麼使用一個標準的單元測試運行器,要麼保持簡單並手動運行測試,但是這樣做的方式可以起作用,而不是無法工作。我想一個簡單的包裝腳本可以作爲一個自定義單元測試跑步者,但是真的,我們正在談論那裏的單線... – abarnert

+0

好的。這只是提醒我留下了一些非常重要的東西。我想能夠使用單元測試或鼻子。 – firstofth300

1

就像abarnert說的那樣,根據腳本的當前名稱,不能執行腳本作爲主要的相對導入。從文檔引用:

請注意,顯式和隱式相對導入均基於當前模塊的 名稱。由於主模塊的名稱始終爲「__main__」,所以用作Python應用程序主模塊的模塊應始終使用絕對導入。

.代表當前包,..代表父包。所以你的一些導入聲明是錯誤的。

from . import person # wrong for no person module in package tests 
from .. import person # wrong for no person module in package app 
from .App.src import person # wrong for no app package in package tests 
from ..App.src import person # wrong for no app package in package app 
from ..src.person import * # right 
from ..src import person # right 
from .src import person # wrong 

您可以參考PEP328作爲相對導入的標準。