ホームページ バックエンド開発 Python チュートリアル Python で循環インポートを修正するさまざまな方法

Python で循環インポートを修正するさまざまな方法

Nov 05, 2024 am 02:21 AM

Python で 循環インポート を見たことがありますか?まあ、これはデザインや構造に何か問題があることを示す非常に一般的なコードの匂いです。

循環インポートの例

循環インポートはどのように行われますか? このインポート エラーは通常、相互に依存する 2 つ以上のモジュールが完全に初期化される前にインポートしようとしたときに発生します。

module_1.py と module_2.py という 2 つのモジュールがあるとします。

# module_1.py
from module_2 import ModY
class ModX:
    mody_obj = ModY()
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
# module_2.py
from module_1 import ModX
class ModY:
    modx_obj = ModX()
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

上記のコード スニペットでは、module_1 と module_2 は両方とも相互に依存しています。

module_1 の mody_obj の初期化は module_2 に依存し、 module_2 の modx_obj の初期化は module_1 に依存します。

これは循環依存関係と呼ばれるものです。両方のモジュールが相互にロードしようとすると、インポート ループでスタックします。

module_1.py を実行すると、次のトレースバックが得られます。

Traceback (most recent call last):
  File "module_1.py", line 1, in <module>
    from module_2 import ModY
  File "module_2.py", line 1, in <module>
    from module_1 import ModX
  File "module_1.py", line 1, in <module>
    from module_2 import ModY
ImportError: cannot import name 'ModY' from partially initialized module 'module_2' (most likely due to a circular import)
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

このエラーは、循環インポートの状況を説明しています。プログラムが module_2 から ModY をインポートしようとしたとき、その時点では module_2 は完全に初期化されていませんでした (moddX を module_1 からインポートしようとする別のインポート ステートメントのため)。

Python で循環インポートを修正するにはどうすればよいですか? Python で循環インポートを削除するにはさまざまな方法があります。

Python での循環インポートを修正する

コードを共通ファイルに移動する

インポートエラーを回避するためにコードを共通ファイルに移動し、そのファイルからモジュールをインポートしてみることができます。

# main.py ----> common file
class ModX:
    pass

class ModY:
    pass
ログイン後にコピー
ログイン後にコピー

上記のコード スニペットでは、ModX クラスと ModY クラスを共通ファイル (main.py) に移動しました。

# module_1.py
from main import ModY

class Mod_X:
    mody_obj = ModY()
ログイン後にコピー
ログイン後にコピー
# module_2.py
from main import ModX

class Mod_Y:
    modx_obj = ModX()
ログイン後にコピー
ログイン後にコピー

ここで、module_1 と module_2 が main からクラスをインポートすることで、循環インポートの状況が修正されます。

このアプローチには問題があり、コードベースが非常に大きくなり、コードを別のファイルに移動するのが危険になる場合があります。

インポートをモジュールの最後に移動します

モジュールの最後に import ステートメントを移動できます。これにより、別のモジュールをインポートする前にモジュールを完全に初期化する時間が与えられます。

# module_1.py
class ModX:
   pass

from module_2 import ModY

class Mod_X:
   mody_obj = ModY()
ログイン後にコピー
ログイン後にコピー
# module_2.py
class ModY:
   pass

from module_1 import ModX
ログイン後にコピー
ログイン後にコピー

クラス/関数スコープ内のモジュールのインポート

クラスまたは関数のスコープ内でモジュールをインポートすると、循環インポートを回避できます。これにより、クラスまたは関数が呼び出された場合にのみモジュールをインポートできるようになります。これは、メモリの使用を最小限に抑えたい場合に関係します。

# module_1.py
class ModX:
  pass

class Mod_X:
   from module_2 import ModY
   mody_obj = ModY()
ログイン後にコピー
ログイン後にコピー
# module_2.py
class ModY:
   pass

class Mod_Y:
   from module_1 import ModX
   modx_obj = ModX()
ログイン後にコピー
ログイン後にコピー

インポート ステートメントを、それぞれ module_1 と module_2 のクラス Mod_X と Mod_Y スコープ内に移動しました。

module_1 または module_2 を実行すると、循環インポート エラーは発生しません。ただし、このアプローチでは、クラスのスコープ内でのみクラスにアクセスできるようになるため、グローバルにインポートを利用することはできません。

モジュール名/エイリアスの使用

このようにモジュール名または単なるエイリアスを使用すると、問題が解決します。これにより、実行時まで循環依存関係を延期することで、両方のモジュールを完全にロードできるようになります。

# module_1.py
from module_2 import ModY
class ModX:
    mody_obj = ModY()
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
# module_2.py
from module_1 import ModX
class ModY:
    modx_obj = ModX()
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

importlibライブラリの使用

importlib ライブラリを使用してモジュールを動的にインポートすることもできます。

Traceback (most recent call last):
  File "module_1.py", line 1, in <module>
    from module_2 import ModY
  File "module_2.py", line 1, in <module>
    from module_1 import ModX
  File "module_1.py", line 1, in <module>
    from module_2 import ModY
ImportError: cannot import name 'ModY' from partially initialized module 'module_2' (most likely due to a circular import)
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
# main.py ----> common file
class ModX:
    pass

class ModY:
    pass
ログイン後にコピー
ログイン後にコピー

Python パッケージの循環インポート

通常、循環インポート 同じパッケージ内のモジュールから取得されます。複雑なプロジェクトでは、パッケージ内にパッケージが存在するため、ディレクトリ構造も複雑になります。

これらのパッケージとサブパッケージには、モジュールへのアクセスを容易にする __init__.py ファイルが含まれています。ここで、モジュール間で意図せず循環依存関係が発生することがあります。

次のディレクトリ構造があります。

# module_1.py
from main import ModY

class Mod_X:
    mody_obj = ModY()
ログイン後にコピー
ログイン後にコピー

パッケージ mainpkg と main.py ファイルがあります。 mainpkg 内には 2 つのサブパッケージ modpkg_x と modpkg_y があります。

modpkg_x および modpkg_y 内の各 Python ファイルは次のようになります。

mainpkg/modpkg_x/__init__.py

# module_2.py
from main import ModX

class Mod_Y:
    modx_obj = ModX()
ログイン後にコピー
ログイン後にコピー

このファイルは、module_1 と module_1_1 から両方のクラス (ModX と ModA) をインポートします。

mainpkg/modpkg_x/module_1.py

# module_1.py
class ModX:
   pass

from module_2 import ModY

class Mod_X:
   mody_obj = ModY()
ログイン後にコピー
ログイン後にコピー

module_1 は module_2 からクラス ModY をインポートします。

mainpkg/modpkg_x/module_1_1.py

# module_2.py
class ModY:
   pass

from module_1 import ModX
ログイン後にコピー
ログイン後にコピー

module_1_1 は何もインポートしません。どのモジュールにも依存しません。

mainpkg/modpkg_y/__init__.py

# module_1.py
class ModX:
  pass

class Mod_X:
   from module_2 import ModY
   mody_obj = ModY()
ログイン後にコピー
ログイン後にコピー

このファイルは、module_2 からクラス ModY をインポートします。

mainpkg/modpkg_y/module_2.py

# module_2.py
class ModY:
   pass

class Mod_Y:
   from module_1 import ModX
   modx_obj = ModX()
ログイン後にコピー
ログイン後にコピー

module_2 は module_1_1 からクラス ModA をインポートします。

main.py ファイル内には次のコードがあります。

root_dir/main.py

# module_1.py
import module_2 as m2

class ModX:
    def __init__(self):
        self.mody_obj = m2.ModY()
ログイン後にコピー

メイン ファイルは module_2 からクラス ModY をインポートします。このファイルは module_2.

に依存しています。

ここでインポート サイクルを視覚化すると、modpkg_x および modpkg_y 内の __init__.py ファイルを無視して次のようになります。

Different Ways to Fix Circular Imports in Python

メイン ファイルが module_2 に依存し、 module_1 も module_2 に依存し、 module_2 が module_1_1 に依存していることがわかります。インポートサイクルはありません。

しかし、モジュールは __init__.py ファイルに依存しているため、__init__.py ファイルが最初に初期化され、モジュールが再インポートされます。

Different Ways to Fix Circular Imports in Python

現在のインポート サイクルは次のようになります。

Different Ways to Fix Circular Imports in Python

これにより、module_1_1 が module_1 に依存するようになりました。これは偽の依存関係です。

この場合は、サブパッケージの __init__.py ファイルを空にし、別の __init__.py ファイルを使用すると、パッケージ レベルでインポートを一元化できます。

# module_1.py
from module_2 import ModY
class ModX:
    mody_obj = ModY()
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

この構造では、mainpkg 内に別のサブパッケージ subpkg を追加しました。

メインpkg/サブpkg/__init__.py

# module_2.py
from module_1 import ModX
class ModY:
    modx_obj = ModX()
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

これにより、内部モジュールを単一のソースからインポートできるようになり、相互インポートの必要性が減ります。

これで、main.py ファイル内の import ステートメントを更新できるようになりました。

root_dir/main.py

Traceback (most recent call last):
  File "module_1.py", line 1, in <module>
    from module_2 import ModY
  File "module_2.py", line 1, in <module>
    from module_1 import ModX
  File "module_1.py", line 1, in <module>
    from module_2 import ModY
ImportError: cannot import name 'ModY' from partially initialized module 'module_2' (most likely due to a circular import)
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

これにより、同じパッケージ内のモジュール間の循環依存関係の問題が解決されます。

結論

Python での循環依存関係またはインポートは コードの匂い であり、コードの深刻な再構築とリファクタリングを示します。

Python での循環依存関係を回避するには、上記の方法のいずれかを試すことができます。


?この記事が気に入ったら、興味があるかもしれない他の記事

✅Flask でのテンプレートの継承と例

✅exec() と eval() の違いと例

✅Python でのグローバル キーワードの使用を理解します。

✅Python の型ヒント: 関数、戻り値、変数。

✅関数定義でスラッシュとアスタリスクが使用される理由。

✅学習率は ML モデルと DL モデルにどのような影響を与えますか?


今回は以上です。

コーディングを続けてください✌✌。

以上がPython で循環インポートを修正するさまざまな方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

LinuxターミナルでPythonバージョンを表示するときに発生する権限の問題を解決する方法は? LinuxターミナルでPythonバージョンを表示するときに発生する権限の問題を解決する方法は? Apr 01, 2025 pm 05:09 PM

LinuxターミナルでPythonバージョンを表示する際の許可の問題の解決策PythonターミナルでPythonバージョンを表示しようとするとき、Pythonを入力してください...

中間の読書にどこでもfiddlerを使用するときにブラウザによって検出されないようにするにはどうすればよいですか? 中間の読書にどこでもfiddlerを使用するときにブラウザによって検出されないようにするにはどうすればよいですか? Apr 02, 2025 am 07:15 AM

fiddlereveryversings for the-middleの測定値を使用するときに検出されないようにする方法

あるデータフレームの列全体を、Python内の異なる構造を持つ別のデータフレームに効率的にコピーする方法は? あるデータフレームの列全体を、Python内の異なる構造を持つ別のデータフレームに効率的にコピーする方法は? Apr 01, 2025 pm 11:15 PM

PythonのPandasライブラリを使用する場合、異なる構造を持つ2つのデータフレーム間で列全体をコピーする方法は一般的な問題です。 2つのデータがあるとします...

プロジェクトの基本と問題駆動型の方法で10時間以内にコンピューター初心者プログラミングの基本を教える方法は? プロジェクトの基本と問題駆動型の方法で10時間以内にコンピューター初心者プログラミングの基本を教える方法は? Apr 02, 2025 am 07:18 AM

10時間以内にコンピューター初心者プログラミングの基本を教える方法は?コンピューター初心者にプログラミングの知識を教えるのに10時間しかない場合、何を教えることを選びますか...

uvicornは、serving_forever()なしでhttpリクエストをどのように継続的に聞いていますか? uvicornは、serving_forever()なしでhttpリクエストをどのように継続的に聞いていますか? Apr 01, 2025 pm 10:51 PM

UvicornはどのようにしてHTTPリクエストを継続的に聞きますか? Uvicornは、ASGIに基づく軽量のWebサーバーです。そのコア機能の1つは、HTTPリクエストを聞いて続行することです...

Investing.comの反クローラーメカニズムをバイパスするニュースデータを取得する方法は? Investing.comの反クローラーメカニズムをバイパスするニュースデータを取得する方法は? Apr 02, 2025 am 07:03 AM

Investing.comの反クラウリング戦略を理解する多くの人々は、Investing.com(https://cn.investing.com/news/latest-news)からのニュースデータをクロールしようとします。

See all articles