2017-05-15 18 views
1

私はPythonで初めてです。以前はSwiftなどの言語を使用していましたが、インポートは大したことではありません。新しいクラスを定義するだけで、別の部分からアクセスできますプログラム。循環インポートを避ける方法

私はこの方法をPythonで使うことはできません。なぜなら、ここでのインポートは逆の働きをするからです。つまり、2つのファイルが互いにインポートされる循環インポートはできません。私は間違った方法で言語を使用するためにこの問題に直面していることを理解していますが、それを避ける方法は理解できません。

ほとんどの場合、2つのクラスを1つのファイルにまとめることでこの問題を解決できますが、それは正しいとは限りません。また、私は "のようなアドバイスをファイルの末尾にインポートステートメントを移動する"のようなアドバイスを見つけましたが、良いアイデアのように感じることはありません。

あなたが望むなら、私はPythonの哲学を理解したいと思います。別のファイルでクラスを作成することを決定するとき、私は自分のプロジェクトをどのように整理し、私はどのような指導を受けるべきですか?

+2

最初に巡回関係がある理由は何ですか? – deceze

+2

両方のモジュールに必要なものがある場合は、それを別のモジュールに入れます。 –

+0

[Pythonで循環インポートを避けるにはどうすればいいですか?](http://stackoverflow.com/questions/7336802/how-to-avoid-circular-imports-in-python) –

答えて

-1

私はPythonでこの方法を使用できません。なぜなら、ここでのインポートは別の方法で動作するからです。つまり、2つのファイルが互いにインポートする循環インポートはできません。

はい、できます。

たちは同じ作業ディレクトリに2つのファイルを持っていると言う:私たちはfile1.py

>>> import file1 
file1 
22 
spam 

FILE1をインポートするときに何が起こるか

#file1.py 
import file2 
x = 22 
y = 'spam' 
print(x) 
print(y) 

#file2.py 
import file1 
print("file1") 

お知らせ.pyインポートs file2.pyfile2.py imports file1.py

+0

周期的なインポートは分岐から解放されていないことに言及することも賢明です。 – direprobs

-2

この問題は、SwiftやJavaプログラムのようにPythonプログラムを作成しているために発生します。そのようなアプローチは決してうまくいきません。すべての言語が異なり、ベストプラクティスが異なります。コードを書いていないコードを書くと、他のPython開発者には見苦しくて解読不能になるだけでなく、言語を楽しむのではなく、苦労しています。

Python開発者のようにコードを構造化するだけです。 1つのモジュールに関連するクラスをグループ化する。まれにインポートサイクルを回避することが難しい(ほとんど起こらない)場合は、グローバルスコープではなく関数またはメソッドの依存関係をインポートしてください。

+1

あなたは特定の情報や有用な助言を与えることなく、私の質問を繰り返すだけです。 –

+0

私はあなたに助言を与えました:循環的な依存関係を避けるために関数またはメソッドレベルでインポートできます。 –

0

あなたは確かにchildparentparentからchildにインポートできます。この作業を行うための鍵はparentモジュールが部分的にロードされるのは、Pythonがモジュールレベルコードchildを実行しているときにのみロードされるため、childはモジュールレベルのコードからparentに深くプローブしないことです。(parent実行のモジュールレベルで

  1. コードは、それがchildをロードするステートメントを達するまでimport child次のいずれか

    は、ここでは、(最初​​にロードされるparentを想定)childからparentparentからchildをインポートするときに何が起こるかですまたはfrom child import something)。 "モジュールレベル"とは、クラスや関数定義に含まれていないステートメントを意味します。モジュールレベルで定義されたクラスと関数も、モジュール内のオブジェクトとして作成されます。ただし、関数とクラスメソッド自体はまだ実行されません。

  2. parentのコードレベルでimport childの文(または同等のもの)を取得すると、parentコードの実行が停止し、childにモジュールレベルのコードが実行されます。 childimport parentまたはfrom parent import somethingparentをインポートした場合、部分的に構成された現在の状態のparentモジュールが得られます。したがって、childのモジュールレベルのコードでは、の下に定義されたオブジェクトには、parent.pyにアクセスできません。
  3. childのモジュールレベルコードの実行が終了すると、制御はimport childステートメントの下のparentに戻り、モジュールレベルコードのすべてがparentで実行されます。

childのモジュールレベルのコードは、(child負荷parentが部分的にしか完了しているので)import child文の後parentで定義されているオブジェクトにアクセスしようとすると、このプロセスはあなたに迷惑を与えるだろう。これを解決するには、childのモジュールレベルでparentをインポートしますが、childparentの読み込みが完了するまで、parentのオブジェクトをchildから遅延させることです。特に、childのモジュールレベルコードでfrom parent import somethingを使用する代わりに、import parentを使用し、の関数またはメソッドコードの中からparent.somethingにアクセスする必要があります。 childparentの実行が終了するまで、これらの関数とメソッドは実行されないため、parentモジュールのすべての要素が正しく定義されるため、これは安全です。

ここでは、コメントで説明した設定を使用して、私が意味するものの一例を示します。あなたに問題をもたらしているコードについてより多くの情報を提供すれば、私はこれをもっと細かく調整することができます。

バージョン1(動作しません)

__main__.py:

from user import User 
u = User() 

user.py:

from data_manager import DataManager 
... 
class User: 
    def __init__(self, data_manager=None): 
     if data_manager is None: 
      data_manager = DataManager(user=self) 
     self.data_manager = data_manager 

data_manager。PY:

# next line will fail because user.py has been partly loaded 
# and user.User doesn't exist yet 
from user import User 
... 
class DataManager: 
    def __init__(self, user=None): 
     ... 
     if user is None: 
      user = User(data_manager=self) 
     self.user = user 

バージョン2は、(動作する)

__main__.py:

from user import User 
u = User() 

user.py:

import data_manager as dm 
... 
class User: 
    def __init__(self, data_manager=None): 
     if data_manager is None: 
      data_manager = dm.DataManager(user=self) 
     self.data_manager = data_manager 

data_manager.py:

import user as user_module 
... 
# this defines a class which will eventually create an instance 
# of user.User, but it won't try to do that until control returns 
# to __main__.py, by which point the `user` and `data_manager` 
# modules are fully defined 
class DataManager: 
    def __init__(self, user=None): 
     ... 
     if user is None: 
      user = user_module.User(data_manager=self) 
     self.user = user 

クラスの__init__メソッドの参照は、クラスが実際にインスタンス化されるまで解決されないことに注意してください。つまり、user = user_module.User(data_manager=self)行は次のようになります。「現在のモジュールでuser_moduleというオブジェクトを探し、そのオブジェクト内でUser属性を調べ、そのクラスのオブジェクトを作成します。重要なことは、data_managerは、userモジュールを早期に安全にインポートできることです(モジュールはすでに一部分のみ構成されていますが、既に存在しています)。DataManagerオブジェクトがインスタンス化されるまで、上記のコードはuserモジュール内で実際に何も検索しませんこれにより、時間はuser.Userが適切に定義されます。

関連する問題