「cannot import name X (most likely due to a circular import)」の対処

結論を先に。2つのモジュールが互いを import し合っている「循環インポート」が原因です。import を関数の中に移す(遅延 import)か、共通部分を別モジュールに切り出せば直ります。

ImportError: cannot import name 'X' from partially initialized module 'm'
(most likely due to a circular import)

原因

モジュール A が B を、B が A を import していると、片方がまだ初期化の途中なのに相手から名前を取り出そうとして失敗します。エラー文に出るモジュール名から、どの2つが循環しているかが分かります。

対処

  1. import を、ファイル先頭ではなく使う関数の中に移す(遅延 import)。読み込み時点ではなく呼び出し時に解決されるので、循環を避けられます。
def f():
from m import X # 関数内に移す
return X()
  1. 共有している定義を、第3のモジュールに切り出す。A と B の両方が、その共通モジュールを参照する形にします。

  2. from m import Ximport m に変え、m.X の形で使うと、初期化順の問題を避けられることがあります。

まとめ

  • 原因は2モジュール間の循環インポート
  • エラー文のモジュール名で循環している組を特定
  • import を関数内に移す(遅延 import)
  • 共通定義は第3のモジュールに切り出す