回答:
グローバル変数は、それにglobal
割り当てる各関数のように宣言することにより、他の関数で使用できます。
globvar = 0
def set_globvar_to_one():
global globvar # Needed to modify global copy of globvar
globvar = 1
def print_globvar():
print(globvar) # No need for global declaration to read value of globvar
set_globvar_to_one()
print_globvar() # Prints 1
その理由は、グローバル変数は非常に危険であるため、Pythonは、global
キーワードを明示的に要求することで、それが実際に操作していることを確実に理解したいと考えているためだと思います。
モジュール間でグローバル変数を共有する場合は、他の回答を参照してください。
global
キーワードを必要とする理由は、グローバルが危険であることには同意しません。むしろ、それは言語が変数を明示的に宣言することを要求せず、あなたが割り当てない変数が他に指示しない限り関数スコープを持っていると自動的に仮定するからです。global
キーワードは、そうでない場合は、それを伝えるために提供される手段です。
f2()
状態を変更したので、f3()
予期しない何かが発生した可能性がありますか?関数は外部プログラムの状態にとらわれずに動作できます
私があなたの状況を正しく理解している場合、Pythonがローカル(関数)およびグローバル(モジュール)名前空間を処理する方法の結果が表示されます。
次のようなモジュールがあるとします。
# sample.py
myGlobal = 5
def func1():
myGlobal = 42
def func2():
print myGlobal
func1()
func2()
これは42を出力することを期待するかもしれませんが、代わりに5を出力します。すでに述べたように、 ' global
'宣言をに追加するとfunc1()
、func2()
42が出力されます。
def func1():
global myGlobal
myGlobal = 42
ここで起こっていることは、Pythonは、特に明記されていない限り、関数内の任意の場所でに割り当てられた名前はその関数に対してローカルであると想定するということです。名前から読み取るだけで、その名前がローカルに存在しない場合は、含まれているスコープ(モジュールのグローバルスコープなど)で名前を検索しようとします。
myGlobal
したがって、42をnameに割り当てると、Pythonは同じ名前のグローバル変数を隠すローカル変数を作成します。そのローカルはスコープ外になり、戻ったときにガベージコレクションされfunc1()
ます。一方、func2()
(変更されていない)グローバル名以外は何も表示できません。この名前空間の決定は、実行時ではなくコンパイル時に行われることに注意してください。myGlobal
内部func1()
に値を割り当てる前にその値を読み取ると、UnboundLocalError
Pythonはすでにローカル変数である必要があると判断しているため、関連付けられている値はまだありません。しかし、 ' global
'ステートメントを使用することで、ローカルに割り当てるのではなく、別の場所で名前を探すようにPythonに指示します。
(この動作は主にローカル名前空間の最適化によって発生したと思います-この動作がない場合、PythonのVMは関数内に新しい名前が割り当てられるたびに少なくとも3つの名前ルックアップを実行する必要があります(名前がtはすでにモジュール/ビルドレベルで存在します)、これは非常に一般的な操作を大幅に遅くします。)
MyGlobal = 5
x
がローカルであると判断することは、ローカル名が最初に使用される前に値にバインドされているかどうかを実行時にチェックすることとは異なります。
MY_GLOBAL = 5
。Pythonコードのスタイルガイドを参照してください。
名前空間の概念を調べてみてください。Pythonでは、モジュールはグローバルデータの自然な場所です。
各モジュールには独自のプライベートシンボルテーブルがあり、モジュールで定義されたすべての関数によってグローバルシンボルテーブルとして使用されます。したがって、モジュールの作成者は、ユーザーのグローバル変数との偶発的な衝突を心配することなく、モジュール内のグローバル変数を使用できます。一方、あなたが何をしているのかがわかっている場合は、モジュールのグローバル変数を、その関数を参照するのに使用したのと同じ表記で触ることができます
modname.itemname
。
モジュール内でのグローバルの具体的な使用法をここで説明します- モジュール間でグローバル変数を共有するにはどうすればよいですか?、そして完全を期すために、内容はここで共有されます:
単一のプログラム内のモジュール間で情報を共有する標準的な方法は、特別な構成モジュール(しばしばconfigまたはcfgと呼ばれる)を作成することです。アプリケーションのすべてのモジュールに構成モジュールをインポートするだけです。その後、モジュールはグローバル名として使用可能になります。各モジュールのインスタンスは1つしかないため、モジュールオブジェクトに加えられた変更はどこにでも反映されます。例えば:
ファイル:config.py
x = 0 # Default value of the 'x' configuration setting
ファイル:mod.py
import config config.x = 1
ファイル:main.py
import config import mod print config.x
config.x
取り除くことができますか?私が付いてきてx = lambda: config.x
、それからに新しい価値が生まれましたx()
。どういうわけか、持っていることa = config.x
は私にとってトリックをしません。
from config import x
解決しますか?
Pythonは、単純なヒューリスティックを使用して、ローカルとグローバルの間で、変数をロードするスコープを決定します。変数名が割り当ての左側に表示されているが、グローバルとして宣言されていない場合は、ローカルであると見なされます。割り当ての左側に表示されない場合は、グローバルと見なされます。
>>> import dis
>>> def foo():
... global bar
... baz = 5
... print bar
... print baz
... print quux
...
>>> dis.disassemble(foo.func_code)
3 0 LOAD_CONST 1 (5)
3 STORE_FAST 0 (baz)
4 6 LOAD_GLOBAL 0 (bar)
9 PRINT_ITEM
10 PRINT_NEWLINE
5 11 LOAD_FAST 0 (baz)
14 PRINT_ITEM
15 PRINT_NEWLINE
6 16 LOAD_GLOBAL 1 (quux)
19 PRINT_ITEM
20 PRINT_NEWLINE
21 LOAD_CONST 0 (None)
24 RETURN_VALUE
>>>
の割り当ての左側に表示されるbaz foo()
が唯一のLOAD_FAST
変数であることを確認してください。
for
ループのターゲットと、as
in with
およびexcept
ステートメントの後の名前もバインドされます。
as
でexcept
、これは私には明らかではなかった句。ただし、メモリを節約するために自動削除されます。
as ...
が、例外ハンドラーのターゲットを含む、コールスタック全体に沿ったすべてのローカルおよびグローバル名前空間を参照するためです。
関数でグローバル変数を参照する場合は、globalキーワードを使用して、どの変数がグローバルであるかを宣言できます。すべてのケースでこれを使用する必要はありません(ここで誰かが誤って主張しているように)-式で参照されている名前がローカルスコープまたはこの関数が定義されている関数のスコープで見つからない場合、グローバルから検索されます変数。
ただし、関数でグローバルとして宣言されていない新しい変数に割り当てると、その変数は暗黙的にローカルとして宣言され、同じ名前の既存のグローバル変数に影を付ける可能性があります。
また、グローバル変数は、特にOOPがやりすぎである小さなスクリプトの場合、そうでないと主張する一部のOOP熱狂者とは異なり、有用です。
ある関数でグローバル変数を作成した場合、その変数を別の関数でどのように使用できますか?
次の関数を使用してグローバルを作成できます。
def create_global_variable():
global global_variable # must declare it to be a global first
# modifications are thus reflected on the module's global scope
global_variable = 'Foo'
関数を作成しても、実際にはそのコードは実行されません。したがって、次のcreate_global_variable
関数を呼び出します。
>>> create_global_variable()
それが指すオブジェクトを変更することを期待しない限り、それを使用することができます:
例えば、
def use_global_variable():
return global_variable + '!!!'
これで、グローバル変数を使用できます。
>>> use_global_variable()
'Foo!!!'
別のオブジェクトでグローバル変数をポイントするには、もう一度グローバルキーワードを使用する必要があります。
def change_global_variable():
global global_variable
global_variable = 'Bar'
この関数を記述した後、実際に関数を変更するコードはまだ実行されていないことに注意してください。
>>> use_global_variable()
'Foo!!!'
したがって、関数を呼び出した後:
>>> change_global_variable()
グローバル変数が変更されていることがわかります。global_variable
名前は今を指します'Bar'
。
>>> use_global_variable()
'Bar!!!'
Pythonの「グローバル」は真にグローバルではないことに注意してください-モジュールレベルに対してのみグローバルです。したがって、グローバルなモジュールで記述された関数でのみ使用できます。関数は、それらが記述されているモジュールを記憶しているため、他のモジュールにエクスポートされても、グローバル変数を見つけるために、それらが作成されたモジュールを調べます。
同じ名前のローカル変数を作成すると、グローバル変数に影が付きます。
def use_local_with_same_name_as_global():
# bad name for a local variable, though.
global_variable = 'Baz'
return global_variable + '!!!'
>>> use_local_with_same_name_as_global()
'Baz!!!'
しかし、その誤った名前のローカル変数を使用しても、グローバル変数は変更されません。
>>> use_global_variable()
'Bar!!!'
何をしているのかを正確に理解しており、そうする十分な理由がない限り、グローバルと同じ名前のローカル変数の使用は避けてください。私はまだそのような理由に遭遇していません。
コメントのフォローは尋ねます:
クラス内の関数内にグローバル変数を作成し、別のクラス内の別の関数内でその変数を使用したい場合はどうすればよいですか?
ここでは、通常の関数と同じようにメソッドで動作することを示します。
class Foo:
def foo(self):
global global_variable
global_variable = 'Foo'
class Bar:
def bar(self):
return global_variable + '!!!'
Foo().foo()
そしていま:
>>> Bar().bar()
'Foo!!!'
ただし、モジュールの名前空間が混乱しないように、グローバル変数を使用する代わりにクラス属性を使用することをお勧めします。また、self
ここでは引数を使用しないことに注意してください。これらはクラスメソッド(通常のcls
引数からクラス属性を変更する場合に便利)または静的メソッド(no self
またはcls
)である可能性があります。
既存の回答に加えて、これをさらに混乱させる:
Pythonでは、関数内でのみ参照される変数は 暗黙的にグローバルです。変数に関数本体内のどこかに新しい値が割り当てられている場合、その変数はローカルであると見なされます。変数に関数内で新しい値が割り当てられる場合、変数は暗黙的にローカルであり、明示的に「グローバル」として宣言する必要があります。
最初は少し意外ですが、少し考えてみるとこれが説明されます。一方では、割り当てられた変数にグローバルを要求すると、意図しない副作用を防ぐことができます。一方、すべてのグローバル参照にグローバルが必要な場合は、常にグローバルを使用します。組み込み関数またはインポートされたモジュールのコンポーネントへのすべての参照をグローバルとして宣言する必要があります。この混乱は、副作用を特定するためのグローバル宣言の有用性を無効にします。
並列実行では、何が起こっているのか理解していない場合、グローバル変数が予期しない結果を引き起こす可能性があります。マルチプロセッシング内でグローバル変数を使用する例を次に示します。各プロセスが独自の変数のコピーで機能することがはっきりとわかります。
import multiprocessing
import os
import random
import sys
import time
def worker(new_value):
old_value = get_value()
set_value(random.randint(1, 99))
print('pid=[{pid}] '
'old_value=[{old_value:2}] '
'new_value=[{new_value:2}] '
'get_value=[{get_value:2}]'.format(
pid=str(os.getpid()),
old_value=old_value,
new_value=new_value,
get_value=get_value()))
def get_value():
global global_variable
return global_variable
def set_value(new_value):
global global_variable
global_variable = new_value
global_variable = -1
print('before set_value(), get_value() = [%s]' % get_value())
set_value(new_value=-2)
print('after set_value(), get_value() = [%s]' % get_value())
processPool = multiprocessing.Pool(processes=5)
processPool.map(func=worker, iterable=range(15))
出力:
before set_value(), get_value() = [-1]
after set_value(), get_value() = [-2]
pid=[53970] old_value=[-2] new_value=[ 0] get_value=[23]
pid=[53971] old_value=[-2] new_value=[ 1] get_value=[42]
pid=[53970] old_value=[23] new_value=[ 4] get_value=[50]
pid=[53970] old_value=[50] new_value=[ 6] get_value=[14]
pid=[53971] old_value=[42] new_value=[ 5] get_value=[31]
pid=[53972] old_value=[-2] new_value=[ 2] get_value=[44]
pid=[53973] old_value=[-2] new_value=[ 3] get_value=[94]
pid=[53970] old_value=[14] new_value=[ 7] get_value=[21]
pid=[53971] old_value=[31] new_value=[ 8] get_value=[34]
pid=[53972] old_value=[44] new_value=[ 9] get_value=[59]
pid=[53973] old_value=[94] new_value=[10] get_value=[87]
pid=[53970] old_value=[21] new_value=[11] get_value=[21]
pid=[53971] old_value=[34] new_value=[12] get_value=[82]
pid=[53972] old_value=[59] new_value=[13] get_value=[ 4]
pid=[53973] old_value=[87] new_value=[14] get_value=[70]
結局のところ、答えは常に単純です。
以下は、main
定義でそれを表示する簡単な方法を持つ小さなサンプルモジュールです。
def five(enterAnumber,sumation):
global helper
helper = enterAnumber + sumation
def isTheNumber():
return helper
これをmain
定義で表示する方法は次のとおりです。
import TestPy
def main():
atest = TestPy
atest.five(5,8)
print(atest.isTheNumber())
if __name__ == '__main__':
main()
この単純なコードはそのように機能し、実行されます。お役に立てば幸いです。
global_vars
データを初期化しますinit_global_vars
。次に、定義されたグローバル変数ごとにアクセサーメソッドを作成します。私はこれを何度も賛成できることを願っています!ピーター、ありがとう!
使用するすべての関数でグローバル変数を参照する必要があります。
次のように:
var = "test"
def printGlobalText():
global var #wWe are telling to explicitly use the global version
var = "global from printGlobalText fun."
print "var from printGlobalText: " + var
def printLocalText():
#We are NOT telling to explicitly use the global version, so we are creating a local variable
var = "local version from printLocalText fun"
print "var from printLocalText: " + var
printGlobalText()
printLocalText()
"""
Output Result:
var from printGlobalText: global from printGlobalText fun.
var from printLocalText: local version from printLocalText
[Finished in 0.1s]
"""
グローバルをローカル変数に実際に格納するのではなく、元のグローバル参照が参照するのと同じオブジェクトへのローカル参照を作成するだけです。Pythonのほとんどすべてがオブジェクトを参照する名前であり、通常の操作では何もコピーされないことに注意してください。
識別子が事前定義されたグローバルを参照する場合を明示的に指定する必要がなかった場合、おそらく代わりに識別子が新しいローカル変数である場合を明示的に指定する必要があります(たとえば、 'var'コマンドのようなもので) JavaScriptで見られます)。重大で自明ではないシステムでは、ローカル変数がグローバル変数よりも一般的であるため、ほとんどの場合、Pythonのシステムの方が理にかなっています。
あなたは可能性があり、それが存在していたか、それがなかった場合は、ローカル変数を作成する場合は、グローバル変数を使用して、推測しようとした言語を持っています。ただし、これはエラーが発生しやすくなります。たとえば、別のモジュールをインポートすると、その名前のグローバル変数が誤って導入され、プログラムの動作が変更される可能性があります。
同じ名前のローカル変数がある場合は、globals()
関数を使用できます。
globals()['your_global_var'] = 42
続いて、アドオンとして、ファイルを使用して、すべてローカルで宣言されたすべてのグローバル変数を格納し、次にimport as
:
ファイルinitval.py:
Stocksin = 300
Prices = []
ファイルgetstocks.py:
import initval as iv
def getmystocks():
iv.Stocksin = getstockcount()
def getmycharts():
for ic in range(iv.Stocksin):
import ... as ...
ですか?なぜimport ...
ですか?
global
:-) => +1 :-)他の人々が持っているかもしれないこれらの尋問を明確にするためにあなたの答えを編集してください。乾杯
グローバル配列の明示的な要素への書き込みは、グローバル宣言を必要としないようですが、「卸売」への書き込みには次の要件があります。
import numpy as np
hostValue = 3.14159
hostArray = np.array([2., 3.])
hostMatrix = np.array([[1.0, 0.0],[ 0.0, 1.0]])
def func1():
global hostValue # mandatory, else local.
hostValue = 2.0
def func2():
global hostValue # mandatory, else UnboundLocalError.
hostValue += 1.0
def func3():
global hostArray # mandatory, else local.
hostArray = np.array([14., 15.])
def func4(): # no need for globals
hostArray[0] = 123.4
def func5(): # no need for globals
hostArray[1] += 1.0
def func6(): # no need for globals
hostMatrix[1][1] = 12.
def func7(): # no need for globals
hostMatrix[0][0] += 0.33
func1()
print "After func1(), hostValue = ", hostValue
func2()
print "After func2(), hostValue = ", hostValue
func3()
print "After func3(), hostArray = ", hostArray
func4()
print "After func4(), hostArray = ", hostArray
func5()
print "After func5(), hostArray = ", hostArray
func6()
print "After func6(), hostMatrix = \n", hostMatrix
func7()
print "After func7(), hostMatrix = \n", hostMatrix
他のどの回答でも見たことがないので、これを追加します。似たような問題に苦しんでいる人にとっては役立つかもしれません。このglobals()
関数は、変更可能なグローバルシンボルディクショナリを返します。これにより、残りのコードでデータを「魔法のように」使用できるようになります。例えば:
from pickle import load
def loaditem(name):
with open(r"C:\pickle\file\location"+"\{}.dat".format(name), "rb") as openfile:
globals()[name] = load(openfile)
return True
そして
from pickle import dump
def dumpfile(name):
with open(name+".dat", "wb") as outfile:
dump(globals()[name], outfile)
return True
グローバル名前空間から変数をダンプ/ロードするだけです。非常に便利で、大騒ぎせず、大騒ぎしません。Python 3のみであることを確認してください。
globals()
常にローカルコンテキストで使用可能なグローバルを返すため、ここでの変更は別のモジュールに反映されない場合があります。
変更を表示するクラスの名前空間を参照します。
この例では、ランナーはファイル構成のmaxを使用しています。ランナーが使用しているときにテストでmaxの値を変更したい。
main / config.py
max = 15000
main / runner.py
from main import config
def check_threads():
return max < thread_count
tests / runner_test.py
from main import runner # <----- 1. add file
from main.runner import check_threads
class RunnerTest(unittest):
def test_threads(self):
runner.max = 0 # <----- 2. set global
check_threads()
一方はWindows / Mac OS、もう一方はLinuxであるため、さまざまなプラットフォーム/環境でのマルチプロセッシングに関連するグローバルは面倒です。
これを、前に遭遇した問題を指摘する簡単な例で示します。
Windows / MacOとLinuxで物事が異なる理由を理解したい場合は、そのことを知っておく必要があります。新しいプロセスを開始するデフォルトのメカニズムは...
それらはメモリ割り当てと初期化では異なります(ただし、ここでは説明しません)。
問題/例を見てみましょう...
import multiprocessing
counter = 0
def do(task_id):
global counter
counter +=1
print(f'task {task_id}: counter = {counter}')
if __name__ == '__main__':
pool = multiprocessing.Pool(processes=4)
task_ids = list(range(4))
pool.map(do, task_ids)
これをWindowsで実行すると(MacOSでも同様です)、次のような出力が得られます...
task 0: counter = 1
task 1: counter = 2
task 2: counter = 3
task 3: counter = 4
これをLinuxで実行すると、代わりに次のようになります。
task 0: counter = 1
task 1: counter = 1
task 2: counter = 1
task 3: counter = 1