web-dev-qa-db-ja.com

Python:モジュールとその中のクラスの間でグローバル変数を共有する

Pythonのモジュール間でグローバル変数を共有できることは知っています。ただし、これが可能な範囲と理由を知りたいのですが。例えば、

global_mod.py

x = None

mid_access_mod.py

from global_mod import *

class delta:
    def __init__(self):
        print x

bot_modif_mod.py

import mid_access_mod
import global_mod

class mew:
    def __init__(self):
        global_mod.x = 5

def main():
    m = mew()
    d = mid_access_mod.delta()

すべてのモジュールがグローバル変数xを共有している場合でも、Noneが出力されます。これはなぜですか? xはmew()によってbot_modif_mod.pyに割り当てられる前にmid_access_mod.pyで評価されるようです。

35
emish

これは、不変の値(intおよびNone)を使用しているために発生します。変数のインポートは、参照渡しではなく、値渡しのようなものです。

Global_mod.xをリストにして、その最初の要素を操作すると、期待どおりに機能します。

from global_mod import xを実行すると、xglobal_modで持っているのと同じ値を使用して、モジュールにxという名前を作成します。関数やクラスなどの場合、これは期待どおりに機能します。これは、人々が(通常)後でそれらの名前に再割り当てしないためです。

Alexが指摘するように、import global_modを使用し、次にglobal_mod.xを使用すると、問題を回避できます。モジュールで定義する名前はglobal_modで、常に必要なモジュールを参照します。次に、属性アクセスを使用してxで取得すると、xの最新の値が取得されます。

37
Ned Batchelder

from whatever import *notをコードで使用するのに適したイディオムです-これは、インタラクティブセッションで、タイピングを節約するショートカットとして使用することを目的としています。基本的に、その時点でのモジュールのすべての名前を「スナップショット」します。これらの名前のいずれかを再バインドすると、スナップショットが古くなり、あらゆる種類の問題が発生します。そして、それは、惨めなfrom ... import *構文を使用してサインアップしている不可解な混乱の始まりにすぎません。

私のアドバイスが欲しいですか?その構造が既存のものであり、二度と使用しないことについて聞いたことはありません。 import global_mod as mを使用し、その後は常に使用qualifiedm.xなどの名前--修飾名はso単なるベアネームよりもPythonではるかに便利で強力です、それも面白いことではありません。 (importステートメントのas m部分は完全にオプションであり、基本的には簡潔にする目的で存在するか、名前の衝突に関するいくつかの問題を回避するために存在します。便利な場合に使用してください。不利な点はありませんが、必要でないと感じた場合でも、使用を強いられたり、強く勧められたりすることはありません)。

26
Alex Martelli

Ned Batchelderが述べたように、値だけが共有され、実際のオブジェクトは共有されません。参照によってオブジェクトを共有する場合は、おそらくThread-Local Data

例えば:

import threading

g = threading.local()
g.population = '7 Billion'

これで、変数g.populationにアクセスしたり、変数を変更したりすると、アクセスしようとしているスレッドと同じである場合、更新された値が取得されます。

Pythonドキュメント: https://docs.python.org/3/library/threading.html#thread-local-data で詳細を読む

0
Kevin

この問題を解決するには、from global_mod import *import global_mod

そして新しいmid_access_mod.pyは次のようになります:

import global_mod

class delta:
    def __init__(self):
        print global_mod.x

その理由は、 here にあります。

Pythonでの参照と名前のバインディングの動作方法により、モジュールの一部のシンボル(たとえば、foo.bar)をそのモジュールの外部から更新し、他のインポートコードで変更を確認するには、foo aをインポートする必要があります。特定の方法。

0
Chaoz

Xのリストを使用するように例を変更し、リストの割り当て(x [0] = ..)をトップの回答で提案されているとおりに印刷し、印刷が同じ初期値(None)を返しました。これにより、「from global_mod import * "は、変更可能かどうかに関係なく、コピーです。

コメントで示唆されているように、「print global_mod.x =がmid_access_modで使用される場合、「import global_mod」は機能します。

0
knormoyle