循環importとは
循環import(circular import)とは、2つ以上のモジュールが互いに依存し合っている状態を指します。
文字通り、関数とかをお互い参照し合うimportであるわけです。
例えば、モジュールAがモジュールBをインポートし、同時にモジュールBもモジュールAをインポートしているような場合です。
module_a.py
from module_b import function_b
def function_a():
print("Function A")
function_b()
module_b.py
from module_a import function_a
def function_b():
print("Function B")
function_a()
なぜ循環importをしてはならないのか
一方のモジュールが完全に読み込まれる前に他方のモジュールが実行を開始してしまい、期待通りに動作しない場合があります。
これのせいでよくバグります。
また、コードの依存関係が複雑になって、コントリビューターがコードを理解したり保守するのが過酷になります。
それでも循環importしなきゃいけない時がある
型注釈とかをする際にはよく陥りがちです。
循環importを無理やり解決する方法
どうしても循環importが必要な場合で、
かつエラーが発生する場合は以下の方法で何とかできます。
遅延インポート
関数内で必要な時にインポートを行います。
module_a.py
def function_a():
from module_b import function_b
print("Function A")
function_b()
module_b.py
def function_b():
from module_a import function_a
print("Function B")
function_a()
モジュールの共通化
両方のモジュールが依存する共通のインターフェースを別のモジュールとして作成すれば循環はしないようになります。
再設計
そもそもアプリケーションの構造を見直して、循環依存がないようにします。
最後に
循環importは、極力しないべきです。