2017-01-13 4 views
2

私は現在、人口モデルシミュレーションのためのPython 2.7コードをいくつか書いています。私は、循環インポートの問題に遭遇しました。循環インポートを解決するためのソフトウェアアーキテクチャの変更方法は?

モデルは以下の構造を有する:(landscape.pyで)

Islandクラス座標

Celllandscape.pyで)クラス

    と風景細胞の

    • コレクション
    • すべてのランドスケープセルのスーパークラス(JungleSavannahMountainなど)。セルクラスには、このセル内の異なる動物の辞書があります。
    • animal辞書は次のように構成されています

      animals = {AnimalType1: [animal1_inst_1, animal_2_inst_2], 
            AnimalType2: [animal2_inst_1, animal_2_inst_2]} 
      
    • は、各セルの初期animal辞書は、実行時に設定されています。

    Animalanimals.py中)クラス

    • すべての動物の種類のスーパークラス(現在はHerbivoreCarnivore)。
    • すべての動物クラスには、この動物が住むことができるすべての細胞型のリストであるallowed_cellsというクラス変数があります。

      allowed_cells = [landscape.Jungle, landscape.Savannah] 
      

    私の問題はこれです - animals.pyは、動物辞書内のすべてのキーがAnimalサブクラスであるかどうかを確認するためにlandscape.pyにインポートされ、対応するリスト内のすべてのインスタンスは、その動物のクラスのインスタンスである場合。 animals.pyでは、allowed_cellsリストが他の多くのテストに加えて実際のセルクラスを持つことができるようにlandscape.pyがインポートされます。

    私は、コードを実行しようとすると、私はエラーを取得:

    Traceback (most recent call last): 
        File "C:/Users/yngve_000/Documents/INF200/inf200_dag_yngve/PA04/biosim/simulation.py", line 10, in <module> 
        import landscape as landscape 
        File "C:\Users\yngve_000\Documents\INF200\inf200_dag_yngve\PA04\biosim\landscape.py", line 12, in <module> 
        import animals 
        File "C:\Users\yngve_000\Documents\INF200\inf200_dag_yngve\PA04\biosim\animals.py", line 18, in <module> 
        class Animal(object): 
        File "C:\Users\yngve_000\Documents\INF200\inf200_dag_yngve\PA04\biosim\animals.py", line 70, in Animal 
        allowed_cell_types = [landscape.Jungle, landscape.Desert, 
    AttributeError: 'module' object has no attribute 'Jungle' 
    

    私はこのエラーが発生する理由を理解ではなく、どのようにエレガントな方法でそれを削除します。 Animalクラスのis_animal関数を作成し、try/exceptを使用していくつかの回避策を使用することは可能ですが、それは最も控えめに言えば非常にぎこちないようです。

    これにはどのような回避策がありますか?

+0

あなたはそう言います*各セルの初期動物辞書は実行時*に設定されています。両方のモジュールがインポートされた場所にそのコードを移動するだけですか? –

答えて

3

animalslandscapeをインポートすると、動物がどこで暮らすことができるのかがわかります。一方、にはなぜAnimalが必要なのかわかりません。セルにはAnimalが存在しない(存在する)可能性がありますが、各Animalはセル内になければなりません。だから、landscapeから動物のものを取り除こうとするべきであり、このモジュールはランドスケープクラスのみを含むべきです。インスタンス化は別のモジュールで行われ、インスタンス化時にはセルに動物が移入されます。動物リストに__init__の引数を付けます。

サブクラスチェックによってis_animalという形式のチェックを実行できます。私。 DogAnimalから継承する場合、issubclass(Dog, Animal)は、Trueと評価されます。サブクラスとしてabstract base classesregister他のクラスを使用することもできます。

+0

私は風景に動物をインポートしている理由は、ユーザーがcell.add_animal()関数で非動物クラスをセルに追加できないようにするためです。これを防ぐために、isinstance(new_animal、animals.Animal)ならば 'を使用しています:raise ValueError(" ... ")'。 これをすべて削除することをおすすめしますか? –

+0

a_guestが示唆するように、 'animals.Animal' '参照クラス'をマスターファイルの__init__の風景に渡すことができます。私。 master: 'savannah = Landscape.Cell(animals.Animal)'とlandscape: 'isinstance(new_animal、self.referenceAnimal):raise ...' – dodell

+0

ここで@ododellに同意します。 '__init__'でセルを設定する必要があります。あなたが '植物 '(または' Vehicle'sなど)を受け入れるだけの細胞を作りたいとします。静的なデザイン(つまり、 'Animal'sのために静的に設定されたセル)を好むなら、別の' animal_landscape'モジュールを作成して 'landscape'と' animal'をそこにインポートして ' AnimalOnlyCell'は 'isinstance'チェックに' animal.Animal'を使用できます。 –

0

landscape.pyの中にインポートしてください。ファイルの先頭ではなく、の中にというキークラスをチェックしてください。

実際には、一般的なアプローチ - 循環インポートに直面したときにローカルインポートを使用することです。しかし、注意してください - 循環インポートは、あなたのコードがカップリングに問題があることを示すシグナルです。

+0

私たちはPEP-8スタイルのガイドに厳重に縛られているので、これは可能ではないでしょうか。 –

+0

_しかし注意してください。循環インポートは、コードがカップリングに問題があることを示すシグナルです。私はそれにはっきりと同意します。人工ねじれを発明する代わりに、コードを見直して適切に再構成する必要があります。循環インポートは、不適切なソフトウェア設計に対する強いヒントです。コードベースが成長している間、事態はさらに悪化する可能性があります。このような問題は、実現した瞬間に洗練された方法で解決する方が良いでしょう。 @YngveMoe PEP8の後、ローカルインポートには何も問題はありません。 –

+0

@a_guest場合によっては、ローカルインポートを避ける合理的な方法がありません(循環インポートの回避策として)。 –

関連する問題