私は次のディレクトリ構造を持っているとしましょう:
a\
__init__.py
b\
__init__.py
c\
__init__.py
c_file.py
d\
__init__.py
d_file.py
a
パッケージの__init__.py
、c
パッケージがインポートされます。しかし、c_file.py
インポートa.b.d
。
プログラムは、b
が存在しないと言って、c_file.py
インポートしようとするa.b.d
。 (そして、私たちはそれをインポートしている最中だったので、それは本当に存在しません。)
この問題はどのように修正できますか?
Aがcに依存し、cがaに依存する場合、実際には同じユニットではないでしょうか?
Aとcを2つのパッケージに分割した理由を実際に調べる必要があります。いくつかのコードがあるため、別のパッケージに分割する必要があります(両方とも新しいパッケージに依存するが、互いに依存しないようにするため)。 1つのパッケージに。
たとえば、a/__init__.py
:
def my_function():
from a.b.c import Blah
return Blah()
つまり、本当に必要になるまでインポートを延期します。ただし、指摘されているような周期的な依存関係は設計上の問題を示している可能性があるため、パッケージの定義/使用についても詳しく調べます。
私はこれを数回疑問に思いました(通常、お互いについて知る必要があるモデルを扱っているとき)。簡単な解決策は、モジュール全体をインポートしてから、必要なものを参照することです。
ので、代わりに
from models import Student
で、そして
from models import Classroom
他では、ただやる
import models
それらの1つで、models.Classroomを必要なときに呼び出します。
問題は、ディレクトリから実行する場合、デフォルトではサブディレクトリであるパッケージのみがインポート候補として表示されるため、a.b.dをインポートできないことです。ただし、b.dをインポートできます。 bはaのサブパッケージであるため。
本当にc/__init__.py
のa.b.dをインポートしたい場合、システムパスをa上の1つのディレクトリに変更し、a/__init__.py
のインポートをa.b.cに変更することでこれを実現できます。
a/__init__.py
は次のようになります。
import sys
import os
# set sytem path to be directory above so that a can be a
# package namespace
DIRECTORY_SCRIPT = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0,DIRECTORY_SCRIPT+"/..")
import a.b.c
Cのモジュールをスクリプトとして実行する場合、さらに困難が生じます。ここでは、パッケージaとbは存在しません。 cディレクトリの__int__.py
をハックしてsys.pathを最上位ディレクトリにポイントし、c内のモジュールで__init__
をインポートして、フルパスを使用してa.b.dをインポートできます。 __init__.py
をインポートするのは良い習慣だとは思いませんが、私のユースケースではうまくいきました。
次のパターンをお勧めします。これを使用すると、オートコンプリートとタイプヒンティングが適切に機能します。
cyclic_import_a.py
import playground.cyclic_import_b
class A(object):
def __init__(self):
pass
def print_a(self):
print('a')
if __== '__main__':
a = A()
a.print_a()
b = playground.cyclic_import_b.B(a)
b.print_b()
cyclic_import_b.py
import playground.cyclic_import_a
class B(object):
def __init__(self, a):
self.a: playground.cyclic_import_a.A = a
def print_b(self):
print('b1-----------------')
self.a.print_a()
print('b2-----------------')
この構文を使用してクラスAおよびBをインポートすることはできません
from playgroud.cyclic_import_a import A
from playground.cyclic_import_b import B
クラスB __ init __メソッドでパラメーターaの型を宣言することはできませんが、次のように「キャスト」できます。
def __init__(self, a):
self.a: playground.cyclic_import_a.A = a