在網絡上有一堆這些python
循環導入問題。我選擇爲這個線程做出貢獻,因爲這個查詢有一個由Ray Hettinger發表的評論,該評論合法化了一個循環導入的用例,但是建議一個我認爲不是特別好的做法 - 將導入移動到一個方法。
除了赫廷傑的權威,三免責聲明共同反對意見是必要的:
- 我從來沒有用Java編程。我沒有試圖做Java風格。
- 重構並不總是有用或有效。邏輯API有時會規定一個使遞歸導入引用不可避免的結構。請記住,代碼存在於用戶而不是程序員。
- 將相當大的模塊組合會導致可讀性和可維護性問題,這可能比一個或兩個遞歸導入更糟糕。
此外,我相信可維護性和可讀性決定了進口在文件的頂部進行分組,每一個需要的名字只出現一次,那from module import name
風格是優選的(除非是在非常短的模塊名稱很多函數,例如gtk
),因爲它避免了重複的語言混亂,並且使依賴性明確。
因爲這樣,我會將我自己的用例的簡化版本帶到這裏,並提供我的解決方案。
我有兩個模塊,每個模塊定義許多類。 surface
定義了幾何曲面,如平面,球體,雙曲面等。path
定義了平面幾何圖形,如直線,圓雙曲線等。從邏輯上講,這些是不同的類別,重構不是API要求的選項。儘管如此,這兩個類別是親密的。
一個有用的操作是交叉兩個表面,例如,兩個平面的交點是一條線,或者一個平面和一個球的交點是一個圓。
如果,例如,在surface.py
你實現一個交集操作的返回值所需要的直線前進進口:
from path import Line
你:
Traceback (most recent call last):
File "surface.py", line 62, in <module>
from path import Line
File ".../path.py", line 25, in <module>
from surface import Plane
File ".../surface.py", line 62, in <module>
from path import Line
ImportError: cannot import name Line
幾何,飛機被用來定義路徑,畢竟它們可以以三個(或更多)維度任意定向。追溯可以告訴你正在發生的事情和解決方案。
只需使用替代進口語句surface.py
:
try: from path import Line
except ImportError: pass # skip circular import second pass
操作的序列中的追溯仍在進行之中。只是第二次通過,我們忽略了導入失敗。這並不重要,因爲Line
未在模塊級別使用。因此,surface
的必要名稱空間將被加載到path
中。 path
的命名空間解析因此可以完成,允許將其加載到surface
中,完成與from path import Line
的首次對話。因此,surface
的命名空間解析可以繼續並完成,繼續執行其他任何必需的操作。
這是一個簡單而非常清晰的習語。 try: ... except ...
語法清楚而簡潔地記錄了循環導入問題,可以緩解未來可能需要的任何維護。只要重構真的是一個壞主意,就使用它。
沒有必要刪除良好設計的循環導入。將導入移到方法定義中是推遲導入的合理方法。 –