ホームページ  >  記事  >  バックエンド開発  >  Python で循環インポート方法を回避する方法の紹介

Python で循環インポート方法を回避する方法の紹介

巴扎黑
巴扎黑オリジナル
2017-09-16 10:07:481418ブラウズ

大規模な Python プロジェクトでは、不適切なアーキテクチャ設計により、モジュール間の相互参照が発生する可能性があります。以下の記事では、Python の循環インポートの問題を回避する方法に関する関連情報を主に紹介します。必要な方は一緒に参照してください。

はじめに

Python でパッケージを使用する場合、循環インポートの問題が発生するのは非常に一般的です。この問題を説明するために次のパッケージを作成しました:


pkg
 ├── __init__.py
 ├── module_a.py
 └── module_b.py

その中には、

__init__.py があります。 pkg を Python パッケージとして指定します

module_a.py は action_a() 関数を定義します。この関数は、 module_b.py で定義された関数や変数などの module_b.py 内の属性を参照します。 >action_b() 関数。これは、関数や変数などの module_a.py 内の属性を参照します action_a()函数,该函数引用了module_b.py中的一个attribute,如一个函数或变量

module_b.py中定义了一个action_b()函数,该函数引用了module_a.py中的一个attribute,如一个函数或变量

这种情况下,执行该package时会抛出circular import error错误,即循环引用,因为module_a试图去引入module_b时,而module_b首先要引入module_a,这会导致Python解释器无法执行下去。

然而,我们可以通过一些巧妙的方法,让上面的逻辑正常工作,同时避免循环引入的错误。

那么,什么时候它能正常工作,什么时候不能正常工作,而那些能够正常工作的情况又是什么原因呢?

何时它能正常工作?

 1. 在module顶部引入,不要用from,相对引入,只在Python 2中有效

在module的顶部import,如import another_module,module 中的函数以another_module.attribute的方式引用another_module中的函数或变量等。这种方式之所以有效,是由于import another_module是基于当前目录的相对引用,而且是一种隐式引用,如果从另一个package中引入module时,就可以失效了。另外,import another_module这种语法在Python3 中已经不支持了,所以不要在代码中用这种方法来避免循环引入。

如:


# pkg/module_a.py 
from __future__ import print_function
import module_b
 
def action_a():
 print(module_b.action_b.__name__)
 
 
# pkg/module_b.py
from __future__ import print_function
import module_a
 
def action_b():
 print(module_a.action_a.__name__)

2. 在module的顶部引入,不要用from,绝对引入

在module的顶部import,使用从package开始的绝对路径,如import package.another_module,module 中的函数以package.another_module.attribute的方式引用another_module中的函数或变量等。之所以要挂上package name来引入,是由于import .another_module这种形式的“相对引入”会报语法错误,而挂上package的绝对引入,Python 2和3都支持

案例:


# pkg/module_a.py
from __future__ import print_function
import pkg2.module_b
 
def action_a():
 print(pkg2.module_b.action_b.__name__)
 
 
# pkg/module_b.py
from __future__ import print_function
import pkg2.module_a
 
def action_b():
 print(pkg2.module_a.action_a.__name__)

3. 在module底部引入another module的attribute,而非another module,用from

在module的底部import(至少要在被引用的attribute之后import),直接引入another module的attribute,如from package.another_module import attribute,相对引入也支持,如from .another_module import attribute,module中的函数直接使用被引用的attribute即可。

如:


# pkg/module_a.py
from __future__ import print_function
 
def action_a():
 print(action_b.__name__)
 
from .module_b import action_b
 
 
# pkg/module_b.py
from __future__ import print_function
 
def action_b():
 print(action_a.__name__)
 
from .module_a import action_a

4. 函数顶部引入,可以用from

在module的function顶部import,如from package import another_module

この場合、パッケージ エラーの実行時に循環インポートがスローされます module_a が module_b を導入しようとして、 module_b が最初に module_a を導入するため、エラー、つまり循環参照が発生します。これにより、Python インタープリタが実行できなくなります。

ただし、いくつかの賢い方法を使用すると、ループによって発生するエラーを回避しながら、上記のロジックを適切に動作させることができます。

それでは、どのような場合に正常に動作するのか、どのような場合に正常に動作しないのか、また、正常に動作する場合の理由は何でしょうか?


いつになったら正常に動作するようになりますか?

1. モジュールの先頭でインポートします。from、相対インポートは使用しないでください。Python 2 でのみ有効です
import another_moduleなど、モジュールの先頭でインポートします。 >、モジュール内の関数 another_module.attribute の形式で、another_module 内の関数または変数を参照します。この方法が有効な理由は、import another_module がカレントディレクトリを基準とした相対参照であり、他のパッケージからモジュールをインポートすると無効になるためです。さらに、import another_module 構文は Python 3 ではサポートされなくなったため、ループの発生を避けるためにコード内でこのメソッドを使用しないでください。


例:

🎜
# pkg/module_a.py
from __future__ import print_function
 
def action_a():
 from . import module_b
 print(module_b.action_b.__name__)
 
 
# pkg/module_b.py
from __future__ import print_function
 
def action_b():
 from . import module_a
 print(module_a.action_a.__name__)
🎜🎜2. モジュールの先頭でインポートします。from は使用せず、絶対にインポートします。🎜🎜🎜🎜モジュールの先頭でインポートし、パッケージから始まる絶対パスを使用します。 import package .another_module など、モジュール内の関数は、package.another_module.attribute の形式で another_module 内の関数または変数を参照します。インポートするパッケージ名をハングアップする必要がある理由は、パッケージの絶対インポートのハングアップがサポートされている一方で、import .another_module 形式の「相対インポート」では構文エラーが報告されるためです。 Python 2 と 3 の両方で🎜🎜ケース: 🎜🎜🎜🎜
# pkg/module_a.py
from __future__ import print_function
 
def action_a():
 from .module_b import action_b
 print(action_b.__name__)
 
 
# pkg/module_b.py
from __future__ import print_function
def action_b():
 from .module_a import action_a
 print(action_a.__name__)
🎜🎜3. 別のモジュールの代わりに、モジュールの下部に別のモジュールの属性を導入します。 module (少なくとも参照された属性の後にインポート)、package.another_module import 属性 などから、別のモジュール の属性を直接導入します。また、次のような相対インポートもサポートされています。 as from .another_module import 属性、モジュール内 関数は参照された属性を直接使用できます。 🎜🎜🎜例: 🎜🎜🎜🎜rrreee🎜🎜4. 関数の先頭でインポートするには、 from など、モジュールの関数の先頭で from🎜🎜🎜🎜 を使用できます。 package import another_module。モジュールまたは属性のいずれかを導入できます。 🎜🎜🎜 例: 🎜🎜🎜🎜rrreee🎜 または 🎜🎜🎜🎜rrreee🎜 このメソッドは Python 2 および 3 でサポートされていますが、コーディングは十分に洗練されておらず、コードの可読性に影響を与えるため、使用はお勧めできません。 🎜🎜🎜🎜🎜注意🎜 🎜🎜🎜🎜この記事で説明する問題は、Python でパッケージを呼び出すときにループの導入を回避する方法です🎜🎜🎜 Python モジュールがコマンドラインで直接実行される場合、該当する状況は正確には異なります同じ🎜

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

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