2012-11-18 540 views
2

首先,這很可能不是路徑問題。無法導入模塊

我在eclipse中有一個pydev項目。下面是目錄結構:

Genetic-Framework 
    | Genetic-Framework 
    | Genetic 
     | __init__.py 
     | GA.py 
     | crossover.py 
     | fitness.py 
     | individual.py 
     | mutation.py 
     | population.py 
     | selection.py 
     | settings.py 
     | visualization.py 

GA.py,我有以下行:

from Genetic import settings, selection, visualization as vis 

是的,Geneticsys.path。不過,我得到以下錯誤:

File "/.../Genetic-Framework/Genetic-Framework/Genetic/GA.py", line 17, in <module> 
    from Genetic import settings, selection, visualization as vis 
ImportError: cannot import name settings 

然而,當我從那條線,一切進口就好刪除settings

有趣的是,settings.py第一線中是這樣的:

from Genetic import fitness, selection, mutation, crossover, population, GA 

;當我從該行刪除GA,一切似乎都導入就好了。

爲什麼我會收到此錯誤?這是循環進口的一些問題嗎?我怎樣才能解決這個問題?

+2

你需要有一個'__init __。py'文件才能工作。你的路上有一個名爲'Genetic.py'的文件嗎?它可能不會導入您認爲正在導入的內容。 – BrenBarn

+0

There/is/an __init __。py'我把它從我的文章中的dir列表中排除了,因爲我認爲它是不相關的。發佈編輯 – inspectorG4dget

回答

4

是的,這是循環進口的問題。

問題

的問題是,當運行GA.py,它首先嚐試導入settings。這意味着settings.py開始運行,並立即嘗試導入GA

然而,GA已經在裝載過程中,所以GA.py沒有得到第二次運行 - 相反,settings只是用來加載GA已在內存(這是目前大部分是空的,因爲它仍在執行它的進口)。

因此,事情settings嘗試使用出來的東西GA失敗,是因爲他們正在尋找GA的事情尚未確定(因爲GA.py處理已沒有得到過去的進口還)。

這使得settings.py的評估引發異常,這表現爲導入失敗(因爲在導入期間引發的異常導致導入失敗)。

解決方案

a)首先避免這種情況。

一般來說,您應該儘量避免循環導入。它們通常意味着你有非常奇怪的依賴性結構,以後很難調試。

這樣做的一種方法是嘗試找到兩個模塊中都需要的東西,並將它們分解爲另一個可以在另外兩個模塊之間共享的單獨的第三個模塊 - 因此不是在B中使用Ax,而是使用By A,你在A和B中使用Cx和Cy。

b)在加載所有內容之前,不要嘗試從循環導入中使用事物。

你可以做的另一件事是推遲使用從另一個模塊的東西,直到所有的導入完成。換句話說,不要嘗試從頂級代碼引用導入模塊的內容,而是在所有導入完成後,將其放入類初始化程序或稍後可調用的函數中。

例如,而不是此...

import Foo 

class Baz: 
    top_level_variable = Foo.bar 

,你可以這樣做:

import Foo 

class Baz: 
    def __init__(self): 
     self.instance_variable = Foo.bar 

顯然,實例屬性是從類屬性略有不同,但這個想法是實際推遲在所有模塊完成執行之後,必須從其他模塊中查找事件,並從而獲得其內容。還要注意from Foo import bar在這裏會失敗,因爲它在導入時試圖訪問Foo的內容,這是需要避免的。

+0

你做得很好,直到你到了選項b,根本不工作。當你引用一個模塊的內容時,Python並不關心:導入它的這一事實意味着它必須被解析,這導致了循環依賴。然而,將* import *移入'__init__'函數是一個潛在的解決方案。 –

+1

@DanielRoseman:的確,模塊必須被解析,但這並不意味着所有的對象都必須完全可用。你對'from ... import ...'說的是真實的,但是當你使用一個簡單的'import foo'時,只要導入的模塊可以被正確地解析,你可以遠離循環導入,只要你不會嘗試訪問變量,直到模塊加載完成後,它會沒事的。關鍵的是,在上面B的第二個例子中,訪問'Foo.bar'的代碼不會在模塊導入時執行。 – BrenBarn

+0

@BrenBarn釘了它。當導入發生時,不會發生該問題,但當導入模塊嘗試*在導入的模塊中訪問*某些內容時。如果你可以避免這樣的訪問(這必然包括避免'from ... import ...'格式導入),那麼它將起作用。 – Amber