0

紛らわしいタイトルで申し訳ありませんが、タイトルに問題の多くを収めようとしました。


シナリオ:

ModuleAいくつかの Tkinter GUI 要素のクラス定義を含むモジュール (たとえば) があります。これらの要素には、特定のイベント/関数もバインド/バインドされています ( '<Button-1>','<Button-2>'....

今、別のモジュールがあります(たとえばModuleB)。これがメイン(のコア)プログラムです。このモジュールでModuleAは、そのオブジェクトを使用するためにインポートします。のオブジェクトはModuleA配列内に配置されます (たとえばArray1)。Array2また、 の各オブジェクトのデータ メンバーの値を 1 つだけ格納する別の配列 (たとえば) がArray1あり、これらは によって操作されるデータ メンバーEvent Bindingsです。

したがって、問題は、Eventが発生すると、 のオブジェクト ( に格納されているArray1) がModuleA必要に応じて視覚的に応答することですが、バックエンドでは、対応するデータ メンバーの値もそれに応じて更新する必要がありますArray2


要するに:

#ModuleA.py

from ModuleB import foo

class bar
    data = 1
    # some tkinter code 
    # bind mouse click to function foo of ModuleB
    
-------------------------------------------------------

#ModuleB.py

from ModuleA import bar

Array1 = [objects of class bar]
Array2 = [value of data of objects in Array1]

def foo(#obj of class bar)
    # find index of bar object which called this function in Array1
    # accordingly change Array2

私が試したこと:

Event Bindingsオブジェクトのに、必要な配列操作を処理する必要ModuleAな関数 (たとえば ) を追加し、ofを処理する必要があるため で定義されています。しかし、これは私にエラーを与えましたfooModuleBArray2ModuleBglobal name 'foo' is not defined

そのため、クラス定義にModuleAを追加しましglobal fooたが、これも解決しませんでした。

最後に挿入してみましたModuleA

from ModuleB import foo

これは、fooをインポートできないということわざを提起しました(これは、それ自体が循環参照をインポートしImportErrorているためだと思います)ModuleBModuleA


解決策

ModuleA明確に見える解決策の 1 つは、 (クラス定義を含む)全体を にコピーすることModuleBです。しかし、これは常に実用的であるとは限りません。

助けてください。

4

3 に答える 3

1

実際には間違っています。2つのモジュールmoduleAとmoduleBを取るとします。moduleAをmoduleBにインポートする場合、moduleBをmoduleAにインポートすることはできません。そのようにしようとすると、インポートエラーが発生するはずです。

あなたがしている間違った方法を見てみましょう

以下はmoduleA.pyです

import moduleB
print " I am moduleA"
class foo():
     pass

これがmoduleB.pyです

from  moduleA import foo
print "I am moduleB"

ここでmoduleB.pyを実行します

python moduleB.py

ImportErrorが発生しますが、発生した場合は発生しません。

python moduleA.py 

上記のプロセスはまったく間違っています。Pythonはこのタイプのインポートを許可しません。ここでは、インポートのループを作成しています。最初のインポートごとに、モジュール全体のトップレベルコードが実行されるためです。もちろん、Pythonはこれを許可しません。

問題を解決するには、モジュール階層を変更するだけです。

簡単な解決策は次のとおりです。両方のモジュール(moduleAとmoduleB)のコンテンツが必要な場合は、もう1つのモジュールmoduleCを作成し、両方のモジュール(moduleAとmoduleB)をmoduleCにインポートして、必要な処理を実行します。

編集したものを参照してください、あなたは同じことをしています

于 2013-01-15T09:04:30.030 に答える
1

Python での循環インポートは混乱を招く可能性があります。間違えやすいので、できれば避けるのが通常はベストです。ただし、それらは違法ではなく、注意すれば問題なく機能します。

次のように入力すると、インポートプロセスは次のように機能しますimport foo

  1. まず、Python はsys.modulesディクショナリを調べて、モジュールfooが既に読み込まれているかどうかを確認します。その場合、既存のモジュールは単に現在のモジュールの名前空間に配置されます (プロセスはそこで停止します)。
  2. そうでない場合は、foo.pyロードするファイルが見つかるかどうかを確認します。存在しない場合は、ImportErrorが発生し、プロセスが停止します。
  3. ファイルが見つかった場合、新しい空のモジュール オブジェクトが作成さsys.modulesれ、名前の下に配置されfooます。
  4. 次に、Python はファイルを開き、手順 3 で作成したモジュール オブジェクトをローカル名前空間として使用して実行を開始します。

ここで、foo上記のモジュールに独自のimportステートメントがある場合、インポート プロセスは、fooモジュールのコードの実行を続行する前に、他のモジュールをロードして再帰できます。ただし、インポートが処理される前に空のモジュール オブジェクトがsys.modulesディクショナリに追加されるため、完全にループして同じファイルを複数回ロードしようとすることはありません (ほとんどの場合)。

うまくいかないことがいくつかあります。

fooが (他のモジュールによってインポートされるのではなく) スクリプトとして実行されている場合、 の最初のエントリはではなくsys.modules名前の下になります。これは、他の場所からインポートされた場合、同じコードの 2 つのコピーが作成されることを意味します。これは、モジュールが 2 回読み込まれないという一般規則の例外であり、場合によっては不意を突かれる可能性があります。__main__foofoo

また、循環的にインポートされたモジュールが相互にトップレベルのアクセスを行っている場合、それらが間違った順序でインポートされた場合 (または任意の順序で、両方が互いのコンテンツを間違った方法で参照している場合) に問題が発生します。トップレベル)。モジュールのロード時に実行されるコードをできるだけ少なくすることで、ほとんどの問題を回避できます (代わりに関数に入れます!)。次に、すべてがロードされた後、明確に定義されたエントリ ポイントから関数を呼び出します。

したがって、あなたの状況では、ここに私が調べるものがあります:

  1. あなたがしている必要がありますfrom moduleB import fooか?代わりに、後でimport moduleBアクセスできますか? moduleB.fooこれは機能する最も簡単な修正です (ただし、考えられるすべての問題を修正するわけではありません)。
  2. モジュールの最上位で作業を行う必要がありますか? 多くの場合、オブジェクトの作成をトップレベルではなく、ファクトリ関数に入れることができます (これにより、ソリューション #1 がより頻繁に機能します)。実行時にオブジェクトを作成する方法を変更 (またはカスタマイズ) できるようにしたい場合は、後で拡張する方が簡単なので、これはとにかく良い設計アイデアです (別の方法で動作する 2 番目の関数を記述するか、追加するだけです)。ファクトリへの引数)。
  3. コードの一部を 3 番目のモジュールから、ModuleAまたはModuleB3 番目のモジュールに移動できますか? 3 番目のモジュールはいずれもインポートする必要がないため、循環インポートの必要がなくなりますか? これは、何がいつロードされるかという問題全体を回避できるため、多くの場合良いアイデアです。

編集: モジュールの固定バージョンは次のようになります。

ModuleA.py:

import ModuleB

class bar():
    def __init__(self, data):
        self.data = data
        # do something here that accesses ModuleB.foo

ModuleB.py:

import ModuleA

def foo():
    # do whatever

Array1 = [ModuleA.bar(i) for i in range(10)]
Array2 = [whatever]

main.py:

import ModuleB # import order is important here!
import ModuleA

if __name__ == "__main__":
    # do stuff

これは最小限の修正です。ModuleAはクラスのメソッドModuleB.foo内からのみアクセスするため、インスタンスが作成される前に定義されている限り、循環インポートは正常に機能します。bar__init__ModuleB.foobar

インポートを任意の順序で機能させたい場合は、少し注意が必要です。モジュールのトップレベルで作業を行う必要はありません。

ModuleA.py は上記の通りです。

ModuleB.py:

import ModuleA

def foo():
    #do stuff

def setupArrays():
    global Array1, Array2 # lets us create these global variables

    Array1 = [ModuleA.bar(i) for i in range(10)]
    Array2 = [whatever]

main.py:

import ModuleA, ModuleB  # import order doesn't matter

if __name__ == "__main__":
    ModuleB.setupArrays()
    # do stuff

これはまだちょっとしたコツです。循環インポートを完全に解除できれば、おそらくコードをより明白な方法で単純化できます。たとえば、コールバック関数をパラメーターとしてbarクラスのコンストラクターに渡すことができます。

ModuleA.py:

# No import statement here! Circular imports avoided!

class bar():
    def __init__(self, data, callback):
        self.data = data
        # bind stuff to call the callback function provided

モジュール B:

import ModuleA

def foo():
    # do whatever

Array1 = [ModuleA.bar(i, foo) for i in range(10)]
Array2 = [whatever]
于 2013-01-15T10:01:58.547 に答える
0

このリンクを確認してください: http://effbot.org/zone/import-confusion.htm モジュールの最後に import ステートメントを移動して循環参照を処理する方法に関する興味深い段落があります。しかし、私見はそれを処理しようとせず、コードをリファクタリングするだけです;)

于 2013-01-17T14:47:05.837 に答える