web-dev-qa-db-ja.com

クロスモジュール変数を作成する方法は?

__debug__変数は、すべてのモジュールに影響するため、一部便利です。同じように機能する別の変数を作成したい場合、どうすればよいですか?

変数(オリジナルで、「foo」と呼びます)は、あるモジュールでfooを変更すると、他のモジュールでfooが更新されるという意味で、真にグローバルである必要はありません。他のモジュールをインポートする前にfooを設定できれば、同じ値が表示されれば問題ありません。

116
Dan Homerick

私は、この解決策を、形や形を問わず支持しません。ただし、変数を__builtin__モジュールに追加すると、デフォルトで__builtin__-すべてを含む他のモジュールからグローバルとしてアクセスできます。

a.pyに含まれる

print foo

b.pyに含まれるもの

import __builtin__
__builtin__.foo = 1
import a

その結果、「1」が印刷されます。

編集:__builtin__モジュールは、ローカルシンボル__builtins__として利用可能です。これが、これらの2つの答えの間に矛盾がある理由です。また、python3では__builtin__builtinsに名前が変更されていることに注意してください。

108

グローバルなクロスモジュール変数が必要な場合は、単純なグローバルなモジュールレベルの変数で十分です。

a.py:

var = 1

b.py:

import a
print a.var
import c
print a.var

c.py:

import a
a.var = 2

テスト:

$ python b.py
# -> 1 2

実際の例: Djangoのglobal_settings.py (ただし、Djangoアプリ設定は、オブジェクトをインポートすることで使用されますDjango.conf.settings )。

151
jfs

理にかなっている状況がたくさんあり、プログラミングを簡素化して、複数の(密結合された)モジュール間で既知のグローバルを持っていると思います。この精神で、グローバルを参照する必要のあるモジュールによってインポートされるグローバルのモジュールを持つという考えについて少し詳しく説明したいと思います。

そのようなモジュールが1つしかない場合、「g」と名付けます。その中で、グローバルとして扱うすべての変数にデフォルト値を割り当てます。それらのいずれかを使用する各モジュールでは、「from g import var」を使用しません。これは、インポート時にのみgから初期化されるローカル変数のみが生成されるためです。私はほとんどの参照をg.varという形式で作成し、「g」は、他のモジュールからアクセスできる可能性のある変数を扱っていることを常に思い出させてくれます。

そのようなグローバル変数の値がモジュール内の一部の関数で頻繁に使用される場合、その関数はローカルコピーを作成できます:var = g.var。ただし、varへの割り当てはローカルであり、割り当てでg.varを明示的に参照しないとグローバルg.varを更新できないことを認識することが重要です。

モジュールの異なるサブセットで共有されるこのようなグローバルモジュールを複数持つことで、物事をより厳密に制御できることに注意してください。グローバルモジュールに短い名前を使用する理由は、それらの出現によってコードが乱雑になるのを避けるためです。ほんの少しの経験で、彼らはたった1つか2つのキャラクターでニーモニックになります。

たとえば、xがgでまだ定義されていないときにg.xに割り当てを行うことができ、別のモジュールがg.xにアクセスできます。ただし、インタープリターで許可されていても、このアプローチはそれほど透明ではないため、避けています。割り当ての変数名のタイプミスの結果として、誤ってgに新しい変数を作成する可能性がまだあります。 dir(g)の検査は、そのような事故によって生じたサプライズ名を発見するのに役立つ場合があります。

22

モジュールを定義し(「globalbaz」と呼ぶ)、その中に変数を定義します。この「pseudoglobal」を使用するすべてのモジュールは、「globalbaz」モジュールをインポートし、「globalbaz.var_name」を使用して参照する必要があります。

これは、変更の場所に関係なく機能します。インポートの前後に変数を変更できます。インポートされたモジュールは最新の値を使用します。 (これをおもちゃの例でテストしました)

明確にするために、globalbaz.pyは次のようになります。

var_name = "my_useful_string"
22
hayalci

あるモジュールのグローバルを別のモジュールに渡すことができます。

モジュールAで:

import module_b
my_var=2
module_b.do_something_with_my_globals(globals())
print my_var

モジュールBで:

def do_something_with_my_globals(glob): # glob is simply a dict.
    glob["my_var"]=3
9
user394430

通常、グローバル変数は悪い考えですが、__builtins__に割り当てることでこれを行うことができます。

__builtins__.foo = 'something'
print foo

また、モジュール自体は、任意のモジュールからアクセスできる変数です。したがって、my_globals.pyというモジュールを定義すると:

# my_globals.py
foo = 'something'

次に、どこからでもそれを使用できます:

import my_globals
print my_globals.foo

__builtins__を変更するのではなくモジュールを使用することは、通常、この種のグローバルを行うためのよりクリーンな方法です。

7
spiv

モジュールレベルの変数を使用してこれを既に行うことができます。モジュールは、インポート元のモジュールに関係なく同じです。そのため、変数を挿入することが理にかなっているモジュールであれば、その変数をモジュールレベルの変数にして、他のモジュールからアクセスしたり、割り当てたりできます。関数を呼び出して変数の値を設定するか、シングルトンオブジェクトのプロパティにする方が良いでしょう。そうすれば、変数が変更されたときに何らかのコードを実行する必要が生じた場合、モジュールの外部インターフェイスを壊すことなく実行できます。

通常、これは物事を行うのに最適な方法ではありません(グローバルを使用することはめったにありません)が、これが最もクリーンな方法だと思います。

5
intuited

変数が見つからない場合があるという答えを投稿したかった。

周期的なインポートはモジュールの動作を破壊する可能性があります。

例えば:

first.py

import second
var = 1

second.py

import first
print(first.var)  # will throw an error because the order of execution happens before var gets declared.

main.py

import first

これは明らかな例ですが、大規模なコードベースでは、これは非常に紛らわしい場合があります。

3
Jonathan

これは、__builtin__名前空間を変更するように聞こえます。それをするために:

import __builtin__
__builtin__.foo = 'some-value'

__builtins__を直接使用しないでください(余分な「s」に注意してください)-これは辞書またはモジュールになります。これを指摘してくれたΤΖΩΤΖΙΟΥのおかげで、もっと多くの here を見つけることができます。

現在、fooはどこでも使用できます。

一般的にこれを行うことはお勧めしませんが、これを使用するかどうかはプログラマー次第です。

割り当ては上記のように行う必要があり、foo = 'some-other-value'を設定するだけで現在のネームスペースでのみ設定されます。

2
awatts

私は、これが本当に欠けていると感じたいくつかの組み込みプリミティブ関数に使用します。 1つの例は、filter、map、reduceと同じ使用セマンティクスを持つ検索関数です。

def builtin_find(f, x, d=None):
    for i in x:
        if f(i):
            return i
    return d

import __builtin__
__builtin__.find = builtin_find

これが実行されると(たとえば、エントリポイントの近くでインポートすることにより)、すべてのモジュールは明らかに、組み込みのようにfind()を使用できます。

find(lambda i: i < 0, [1, 3, 0, -5, -10])  # Yields -5, the first negative.

注:もちろん、フィルターと別の行で長さゼロをテストしたり、ある種の奇妙な行を減らしたりすることでこれを行うことができますが、私はいつもそれが奇妙だと感じました。

1
Brian Arsuaga

辞書を使用して、モジュール間で変更可能な(またはmutable)変数を実現できました。

# in myapp.__init__
Timeouts = {} # cross-modules global mutable variables for testing purpose
Timeouts['WAIT_APP_UP_IN_SECONDS'] = 60

# in myapp.mod1
from myapp import Timeouts

def wait_app_up(project_name, port):
    # wait for app until Timeouts['WAIT_APP_UP_IN_SECONDS']
    # ...

# in myapp.test.test_mod1
from myapp import Timeouts

def test_wait_app_up_fail(self):
    timeout_bak = Timeouts['WAIT_APP_UP_IN_SECONDS']
    Timeouts['WAIT_APP_UP_IN_SECONDS'] = 3
    with self.assertRaises(hlp.TimeoutException) as cm:
        wait_app_up(PROJECT_NAME, PROJECT_PORT)
    self.assertEqual("Timeout while waiting for App to start", str(cm.exception))
    Timeouts['WAIT_JENKINS_UP_TIMEOUT_IN_SECONDS'] = timeout_bak

test_wait_app_up_failを起動すると、実際のタイムアウト時間は3秒です。

1
foudfou

グローバル変数ではなくクラス名前空間を使用することで、グローバル変数を使用することの欠点のいくつかを回避することが可能かどうか疑問に思いました(たとえば http://wiki.c2.com/?GlobalVariablesAreBad )変数の値を渡すモジュール名前空間。次のコードは、2つのメソッドが本質的に同一であることを示しています。以下で説明するように、クラスの名前空間を使用することにはわずかな利点があります。

次のコードフラグメントは、グローバル/モジュールネームスペースとクラスネームスペースの両方で、属性または変数を動的に作成および削除できることも示しています。

wall.py

# Note no definition of global variables

class router:
    """ Empty class """

このモジュールは、変数をバウンスするために使用されるため、「壁」と呼びます。これは、空のクラス「ルーター」のグローバル変数とクラス全体の属性を一時的に定義するスペースとして機能します。

source.py

import wall
def sourcefn():
    msg = 'Hello world!'
    wall.msg = msg
    wall.router.msg = msg

このモジュールは、wallをインポートし、メッセージを定義し、2つの異なるメカニズム(1つはグローバル経由で、もう1つはルーター機能経由)で発信する単一の関数sourcefnを定義します。変数wall.msgおよびwall.router.messageは、それぞれの名前空間で初めてここで定義されることに注意してください。

dest.py

import wall
def destfn():

    if hasattr(wall, 'msg'):
        print 'global: ' + wall.msg
        del wall.msg
    else:
        print 'global: ' + 'no message'

    if hasattr(wall.router, 'msg'):
        print 'router: ' + wall.router.msg
        del wall.router.msg
    else:
        print 'router: ' + 'no message'

このモジュールは、2つの異なるメカニズムを使用してソースから送信されたメッセージを受信する関数destfnを定義します。変数 'msg'が存在しない可能性があります。 destfnは、表示された変数も削除します。

main.py

import source, dest

source.sourcefn()

dest.destfn() # variables deleted after this call
dest.destfn()

このモジュールは、以前に定義された関数を順番に呼び出します。 dest.destfnへの最初の呼び出しの後、変数wall.msgおよびwall.router.msgはもう存在しません。

プログラムからの出力は次のとおりです。

global:Hello world!
ルーター:Hello world!
global:メッセージなし
ルーター:メッセージなし

上記のコードフラグメントは、モジュール/グローバルメカニズムとクラス/クラス変数メカニズムが本質的に同一であることを示しています。

多くの変数を共有する場合、名前空間の汚染は、いくつかの壁タイプのモジュールを使用して管理できます。 wall1、wall2など、または単一のファイルで複数のルータータイプクラスを定義することによって。後者はやや整理整頓されているため、クラス変数メカニズムを使用する場合にはおそらくわずかな利点があるにすぎません。

0
robertofbaycot