循環インポートの検出 質問する

循環インポートの検出 質問する

私は約 30 個のユニークなモジュールを含むプロジェクトに取り組んでいます。あまり適切に設計されていないため、プロジェクトに新しい機能を追加するときに循環インポートを作成することがよくあります。

もちろん、循環インポートを追加したときは、それに気づきません。 をAttributeError: 'module' object has no attribute 'attribute'明確に定義した場所でエラーが発生した場合、循環インポートを行ったことがかなり明白な場合があり'attribute'ます。しかし、使用方法が原因でコードが例外をスローしないこともあります。

それで、私の質問はこうです:

循環インポートがいつどこで発生しているかをプログラムで検出することは可能ですか?

今のところ私が考えられる唯一の解決策は、importTrackingdictimportingModulesimportInProgress(file)、 を増分してimportingModules[file]1 より大きい場合にエラーをスローする関数、importComplete(file)および を減分する関数を含むモジュールを用意することですimportingModules[file]。他のすべてのモジュールは次のようになります。

import importTracking
importTracking.importInProgress(__file__)
#module code goes here.
importTracking.importComplete(__file__)

でも、それは本当にひどいですね。もっと良い方法があるはずですよね?

ベストアンサー1

すべてのモジュールを変更する必要がないように、インポート追跡機能をインポートフック、またはカスタマイズされた では__import__、組み込みの を挿入することができます。後者の場合は、__import__インポートするモジュールがすでに にある場合でも が呼び出されるためsys.modules、循環インポートの場合のように、より適切に機能する可能性があります。

実装には、単に「インポート中」のモジュールのセットを使用します。たとえば、次のようになります (benjaoming 編集: オリジナルから派生した実用的なスニペットを挿入)。

beingimported = set()
originalimport = __import__
def newimport(modulename, *args, **kwargs):
    if modulename in beingimported:
        print "Importing in circles", modulename, args, kwargs
        print "    Import stack trace -> ", beingimported
        # sys.exit(1) # Normally exiting is a bad idea.
    beingimported.add(modulename)
    result = originalimport(modulename, *args, **kwargs)
    if modulename in beingimported:
        beingimported.remove(modulename)
    return result
import __builtin__
__builtin__.__import__ = newimport

おすすめ記事