2

しばらくの間Pythonプログラムを書き始めましたが、あまり得意ではありません。現在、問題が発生しています。少なくとも私にとっては、非常に奇妙に思えます。

A.pyとという2つのソースファイルがあると仮定しますB.py。それらの内容は次のとおりです。

A.py

import B

__global__ = 'not set yet'

class Data:
    __var__ = 'not set yet'

def init():
    global __global__
    __global__ = 'value set for global'
    Data.__var__ = 'value set for class var'

if __name__ == '__main__':
    init()

    t = B.Test()
    t.display()

    print '============================'
    print 'global(in A):    ' + __global__
    print 'class var(in A): ' + Data.__var__

B.py

import A

class Test:
    def __init__(self):
        self.glo = A.__global__
        self.var = A.Data.__var__

    def display(self):
        print 'global:          ' + self.glo
        print 'class var:       ' + self.var
        print '============================'
        print 'global(in B):    ' + A.__global__
        print 'class var(in B): ' + A.Data.__var__

次に実行python A.pyしました。出力は次のとおりです。

global:          not set yet
class var:       not set yet
============================
global(in B):    not set yet
class var(in B): not set yet
============================
global(in A):    value set for global
class var(in A): value set for class var

私の意見では、最初の4つの出力は最後の2つの出力と一致するはずですが、実際はそうではなく、値はクラスとメソッドの定義中に設定され、変更できないようです。これは、Javaなどの他の多くの言語とは大きく異なります。それで、誰かがこれを説明するのを手伝うことができますか、それを理解するのを助けるために私にいくつかのリンクを貼り付けてください?そして、これを解決するための回避策はありますか?

前もって感謝します、

ケルビン

==============編集==============

@ icktoofay、@ hop、@ RocketDonkeyに感謝します。以下のコードを試した後、根本的な原因を見つけました。

import sys
import A
import __main__

__global__ = 'not set yet'

class Data:
    __var__ = 'not set yet'

def init():
    global __global__
    __global__ = 'value set for global'
    Data.__var__ = 'value set for class var'

if __name__ == '__main__':
    init()

    for key in sys.modules.keys():
        if key in ['__main__', 'A']:
            print key + ' : ' + sys.modules[key].__file__
    print '===================='
    print 'A: ' + A.__global__
    print 'A: ' + A.Data.__var__
    print '===================='
    print __main__.__global__
    print __main__.Data.__var__

出力は次のとおりです。

__main__ : A.py
A : D:\test\python\A.py
====================
A: not set yet
A: not set yet
====================
value set for global
value set for class var

これは、ファイルA.pyが2回インポートされたためです。1つは名前が付けられ__main__、もう1つは名前が付けられA、値はモジュールで変更されました__main__が、モジュールBの場合、値はモジュールから取得されるAため、値は変更されません。

Pythonのモジュールインポートについては、さらに深く掘り下げる必要があります。:-D

4

2 に答える 2

3

メインスクリプトであるモジュールの1つと組み合わせた循環インポート(Aimports BBimports )が問題です。A

Pythonがモジュールをインポートする方法

Pythonにモジュールのインポートを依頼すると、最初にsys.modulesその名前のモジュールがすでに存在するかどうかを確認します。もしそうなら、それはそのモジュールを使用するだけです。その名前のモジュールがない場合は、新しいモジュールオブジェクトを作成し、に配置してsys.modules、そのモジュールで適切なPythonコードを実行します。

メインスクリプト

Pythonスクリプトで使用される一般的なイディオムがあります:ユビキタス

if __name__ == '__main__':

Pythonがメインスクリプトを実行する場合、Pythonはそのモジュールを.という名前__main__でインポートします。

メインスクリプトが他のモジュールと同じように処理する場合はまったく問題ありませんが、他のモジュールがメインモジュールに対して再度処理を実行する場合は、問題が発生します。メインモジュールを再度インポートするスクリプトは、おそらく通常の名前でインポートしています(この場合、A)。残念ながら、すでにロードされているモジュールには名前が付けられていませんA。名前は__main__

ソリューション

非常に簡単な解決策は、メインモジュールに対する他のモジュールの依存関係を削除することです。そうすれば、この直感的でない動作に遭遇することはありません。mainこれを行う1つの方法は、メインスクリプトを、別のモジュールの関数などを呼び出すスタブにすることです。

別の解決策は、メインスクリプトをsys.modules手動で変更して、それ自体を別の名前で配置することです。これは少しハッキーですが、機能します。

sys.modules['A'] = sys.modules[__name__]

今、あなたは知っています。

于 2013-01-08T02:53:52.747 に答える
1

+1 to @icktoofay-私はその答えに私のものよりも多くの株を入れます、それでそれはプロセスの私の確かに経験の浅い理解であるため、これを一粒の塩と一緒に取ってください:

他の人が言ったように、あなたの主な問題は循環輸入です。他の人はもっと賢くコメントしますが、起こっていることの要点は次のとおりです。

  1. import B-これはA.py`を実行するとすぐに発生するため、B.pyに移動すると、すぐにインポートAが見つかります。
  2. 現在Aの名前空間に別の名前があるため、再度インポートされます(これを確認するには、print __name__上記import Bに追加しA.pyてください-2つの異なる名前が表示されます)。
  3. AインポートされるBと、__global__ = 'not seen yet'宣言が含まれるため、と言うと、その変数を取得します(このバージョンのself.glo = A.__global__特定のコードは実行されないため、変更された変数ではありません)。A
  4. と同じです-このモジュールA.Data.__var__は実行されていないため(「メイン」ではないため)、まだ何も変更されていません。initA
  5. 上記のように、理由がわかり、A.__global__A.Data.__var__まだ表示されていません」も表示されます。これらは変更されておらず、上記の変数と同じです。
  6. Aこのセクションのコードは__main__、指定したすべての初期化を実行するそのバージョンのモジュールで動作しているため、通常どおり実行されます。
于 2013-01-08T03:13:50.667 に答える