質問
__ debug __
変数は、すべてのモジュールに影響するため、一部便利です。同じように機能する別の変数を作成する場合、どうすればよいですか?
変数(オリジナルにして、「foo」と呼ぶ)は、あるモジュールでfooを変更した場合、他のモジュールでfooが更新されるという意味で、真にグローバルである必要はありません。他のモジュールをインポートする前にfooを設定できれば、同じ値が表示されれば大丈夫です。
解決
私は、この解決策をいかなる形、形、形でも支持しません。ただし、変数を __ builtin __
モジュールに追加すると、デフォルトで __ builtin __
を含む他のモジュールからグローバルにアクセスできます。 。
a.pyに含まれる
print foo
b.pyに含まれる
import __builtin__
__builtin__.foo = 1
import a
結果は、" 1"印刷されます。
編集: __ builtin __
モジュールは、ローカルシンボル __ builtins __
として利用できます。これが、これらの2つの回答の間に矛盾がある理由です。また、 __ builtin __
はpython3で builtins
に名前が変更されていることに注意してください。
他のヒント
グローバルなモジュール間変数が必要な場合は、単純なグローバルなモジュールレベルの変数で十分です。
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アプリの設定は、 object django.conf.settings
)。
モジュールを定義し(" globalbaz"と呼ぶ)、その中に変数を定義します。この" pseudoglobal"を使用するすべてのモジュール" globalbaz"をインポートする必要がありますモジュール、および" globalbaz.var_name"
を使用して参照しますこれは、変更の場所に関係なく機能します。インポートの前後に変数を変更できます。インポートされたモジュールは最新の値を使用します。 (おもちゃの例でこれをテストしました)
説明のため、globalbaz.pyは次のようになります。
var_name = "my_useful_string"
理にかなっている状況がたくさんあり、プログラミングを簡素化して、複数の(密結合された)モジュール間で既知のグローバルをいくつか持つと信じています。この精神で、私はそれらを参照する必要があるモジュールによってインポートされるグローバルのモジュールを持つという考えについて少し詳しく述べたいと思います。
そのようなモジュールが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)の検査は、そのような事故によって生じたサプライズ名を発見するのに役立つ場合があります。
1つのモジュールのグローバルを他のモジュールに渡すことができます:
モジュール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
通常、グローバル変数は悪い考えですが、 __ builtins __
に割り当てることでこれを行うことができます:
__builtins__.foo = 'something'
print foo
また、モジュール自体は、任意のモジュールからアクセスできる変数です。したがって、 my_globals.py
というモジュールを定義すると:
# my_globals.py
foo = 'something'
その後、どこからでも使用できます:
import my_globals
print my_globals.foo
__ builtins __
を変更するのではなくモジュールを使用することは、一般的にこの種のグローバルを行うためのよりクリーンな方法です。
モジュールレベルの変数を使用してこれを既に実行できます。モジュールは、インポート元のモジュールに関係なく同じです。そのため、変数を入れるのが理にかなっているモジュールであれば、その変数をモジュールレベルの変数にして、他のモジュールからアクセスしたり、割り当てたりすることができます。関数を呼び出して変数の値を設定するか、シングルトンオブジェクトのプロパティにする方がよいでしょう。そうすれば、変数が変更されたときに何らかのコードを実行する必要が生じた場合、モジュールの外部インターフェイスを壊すことなく実行できます。
これは通常、物事を行うのに最適な方法ではありません—グローバルを使用することはほとんどありません—しかし、これが最もクリーンな方法だと思います。
変数が見つからない場合があるという回答を投稿したい。
サイクリックインポートはモジュールの動作を破壊する可能性があります。
例:
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
これは明らかな例ですが、大規模なコードベースでは、これは本当に紛らわしい場合があります。
これは、 __ builtin __
名前空間を変更するように聞こえます。それを行うには:
import __builtin__
__builtin__.foo = 'some-value'
__ builtins __
を直接使用しないでください(余分な" s"に注意してください)-明らかにこれは辞書またはモジュールになります。 ΤΖΩΤΖΙΟΥこれを指摘するために、こちら。
現在、 foo
はどこでも使用できます。
これを一般的に行うことはお勧めしませんが、これを使用するのはプログラマー次第です。
上記のように割り当てる必要があり、 foo = 'some-other-value'
を設定するだけで、現在のネームスペースでのみ設定されます。
私は、これが実際に不足していると感じたいくつかの組み込みプリミティブ関数に使用します。 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.
注:もちろん、これを行うにはフィルターと別の行で長さゼロをテストするか、ある種の奇妙な行を減らしますが、私はいつもそれが奇妙だと感じました。
辞書を使用して、モジュール間で変更可能な(または可変)変数を実現できます:
# 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秒です。
グローバル変数を使用することの欠点のいくつかを回避することが可能かどうか疑問に思いました(例: 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'
このモジュールは、 destfn
という関数を定義します。この関数は、2つの異なるメカニズムを使用して、ソースから送信されたメッセージを受信します。変数 '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!
グローバル:メッセージなし
ルーター:メッセージなし
上記のコードフラグメントは、モジュール/グローバルメカニズムとクラス/クラス変数メカニズムが本質的に同一であることを示しています。
多くの変数を共有する場合、名前空間の汚染は、いくつかの壁タイプのモジュールを使用して管理できます。 wall1、wall2など、または単一のファイルで複数のルータータイプクラスを定義することによって。後者はやや整頓されているため、クラス変数メカニズムを使用する場合の限界的な利点を示している可能性があります。