2011-03-08 48 views
3

我知道有幾個類似的問題,但我很努力去理解我得到的錯誤,瀏覽文檔和類似的問題還沒有幫助。如果有的話,類似的問題讓我覺得我所做的是對的。瞭解Python中的導入鏈

我有以下文件:

的src/main.py

from pack import pack 

if __name__ == '__main__': 
    pack.exec("Hello Universe!") 

的src /包/ pack.py

import util 

def exec(text): 
    util.write(text) 

if __name__ == '__main__': 
    exec("Hello World!") 

SRC /包/ util.py

def write(text): 
    print(text) 

* 的src /包/ _ INIT _.py *

EMPTY FILE 

當我從src/pack目錄運行python pack.py ,它工作(打印「Hello World!」)。然而,當我從src目錄運行python main.py我得到以下異常:

Traceback (most recent call last): 
    File ".../src/main.py", line 1, in <module> 
    from pack import pack 
    File ".../src/pack/pack.py", line 1, in <module> 
    import util 
ImportError: No module named util 

如果我在pack.py更改導入線from . import util的建議,有效相反occours。 main.py運行成功,但是現在pack.py失敗,籌措:

Traceback (most recent call last): 
    File ".../src/pack/pack.py", line 1, in <module> 
    from . import util 
ValueError: Attempted relative import in non-package 

我本來以爲進口相對於當前位置,因此你應該能夠建立這樣的進口鏈條。對我來說,看起來很奇怪,根據程序啓動的位置,模塊應該導入一個兄弟文件。

有人可以解釋爲什麼這種錯誤發生在一種方式,而不是另一種方式,並且如果有某種方式允許此文件結構運行,無論我是想從main.py還是pack.py運行?

+0

什麼版本的Python? – 2011-03-08 01:53:46

+0

Win7 32bit上的Python 3.1.3 – dimo414 2011-03-08 01:55:39

回答

5

在這兩種情況下,導入工作都會遇到麻煩。這是因爲在一種情況下,您將pack.py作爲主文件運行,而在另一種情況下,將其作爲程序包的一部分運行。

當您將其作爲獨立腳本python pack.py運行時,「pack」目錄被添加到PYTHONPATH中,這意味着您可以導入其中的任何模塊。因此,import util將工作。

當您運行python main.py時,將src目錄添加到您的PYTHONPATH中。這意味着src中的任何模塊或程序包(例如pack目錄)現在都可以導入。因此from pack import pack。但是,要訪問util.py,您現在需要執行from pack import util。正如你注意到的那樣,你也可以在pack.py之內做from . import util

但是你不能同時做到這兩點。 src/是主目錄或src/pack是。

顯而易見的錯誤解決方案是讓main.py將src/pack目錄添加到PYTHONPATH中。這將起作用,但這不是一個好主意。做到這一點的正確方法是下定決心。 src/pack是一個應該通過import pack導入的模塊還是隻是一個包含一堆Python腳本的文件夾?決定! :-)

我認爲在這種情況下它'很明顯,src/pack應該是一個模塊。所以,然後把它當作一個模塊來對待,並確保它像模塊一樣可用。那麼即使運行pack.py作爲主要腳本,您也可以from pack import util

你是怎麼做的?那麼,基本上你要麼在你的站點包中安裝pack模塊,要麼你將src目錄添加到PYTHONPATH中。最後一個是你在開發過程中想要的。您可以使用export PYTHONPATH=<path>手動執行此操作,也可以讓您的testrunner爲您執行此操作。你沒有一個testrunner?那麼你應該,但這是另一個問題。 :)

對於永久安裝它,一旦你不做開發了,看看Distribute。它包括一個testrunner。 ;)

+0

你可以詳細說明「src/pack應該是一個模塊」嗎?你是說目錄本身應該是一個模塊? – dimo414 2011-03-15 02:51:12

+0

@ dimo414:我的意思是它應該有一個'__init __。py'。這使得它表現得像一個模塊。嚴格地說,作爲一個模塊的目錄的python術語是「包」,但這往往會混淆包括我在內的人。 :) – 2011-03-15 15:15:33

+0

@LennartRegebro:術語確實令人困惑。作爲一個試圖找到一個好的心智模式的新手,我的當前是:「包是一個可以包含子模塊的模塊」***。但是,它們仍然是模塊:您可以單獨導入它們「導入包」並使用它們的對象(在__init __。py中)和子模塊。 '__init __。py'使目錄被視爲一個包。 – MestreLion 2012-04-13 18:40:19

0

correct documentation什麼都不支持你的理論,這種形式的導入應該工作。

+0

好的,謝謝,修復了這個鏈接。盡我所知,然而,我所擁有的代碼仍應該運行。 – dimo414 2011-03-08 01:57:26

+0

@ dimo414:你*看過*正確的​​文檔嗎? – 2011-03-08 01:58:14

+0

我做過了,關於這個話題我不太清楚。我的問題的目的是在包中運行/退出文件在我看來似乎違反直覺,我試圖理解這方面的最佳實踐,如果有任何方法可以解決我的具體問題,能夠運行進出包。 – dimo414 2011-03-08 02:19:04

2

您在包目錄中缺少__init__.py。

在您的包目錄中創建一個名爲__init__.py的空文件。

+1

+1 - 「__init __。py」文件將告訴python該目錄是一個包。你可以在'__init __。py'文件中指定你想要加載或者不加載的東西,但是一個空文件是足夠的並且可以工作。 – laurent 2011-03-08 00:54:58

+0

請原諒我不提及它,但有一個空的'__init __。py'文件。 – dimo414 2011-03-08 01:50:38

4

您的鏈接是python 2.7文檔,但看起來您使用的是Python 3.x.

請參閱:http://docs.python.org/py3k/以獲取正確的文檔。

Python 3刪除隱式相對導入。也就是說,不能再以相同的方式在同一個模塊中導入包。

您需要使用from . import util,這是一個明確的相對導入並且是允許的。 import X不再檢查當前目錄。相反,它只檢查sys.path中的條目。這包括啓動腳本的目錄和python的標準庫。

+0

好的,謝謝你向我解釋。麻煩的是,現在它不工作/其他/方式。運行'main.py'有效,但'pack.py'不行。 – dimo414 2011-03-08 02:15:42

+1

@ dimo414:那是因爲你應該使用'-m'運行'pack.pack'。 – 2011-03-08 02:17:17

+1

@ dimo414,運行腳本包內的腳本是皺眉。你想運行的任何腳本都不應該放在包中。 – 2011-03-08 03:27:24