関数でのグローバル変数の使用


3114

関数でグローバル変数を作成または使用するにはどうすればよいですか?

1つの関数でグローバル変数を作成した場合、そのグローバル変数を別の関数でどのように使用できますか?アクセスを必要とする関数のローカル変数にグローバル変数を格納する必要がありますか?

回答:


4246

グローバル変数は、それに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キーワードを明示的に要求することで、それが実際に操作していることを確実に理解したいと考えているためだと思います。

モジュール間でグローバル変数を共有する場合は、他の回答を参照してください。


838
グローバルを「とても危険」と呼ぶのは極端な誇張です。グローバルは、これまで存在し、これからも存在するすべての言語で完全に問題ありません。彼らは彼らの場所を持っています。あなたが言うべきだったのは、プログラミングの手がかりがなければ問題を引き起こす可能性があるということです。
アンソニー

207
かなり危険だと思います。ただし、Pythonでは「グローバル」変数は実際にはモジュールレベルであり、多くの問題を解決します。
ファビオサントス

246
Pythonがglobalキーワードを必要とする理由は、グローバルが危険であることには同意しません。むしろ、それは言語が変数を明示的に宣言することを要求せず、あなたが割り当てない変数が他に指示しない限り関数スコープを持っていると自動的に仮定するからです。globalキーワードは、そうでない場合は、それを伝えるために提供される手段です。
Nate CK

7
@avgvstvs:グローバルなしで同じプログラムを実装している場合でも、コードパスの数は同じです。あなたがした議論はグローバルに対するものではありません。
軌道の軽さのレース

13
@LightnessRacesinOrbit要点がわかりません。グローバル変数を削除すると、複雑な要素が削除され、実行中のさまざまな時点で任意の関数がプログラムの状態を変更できなくなります。そのため、その変数に依存している他の関数には感知できない方法で実行が変更されます。「f2()状態を変更したので、f3()予期しない何かが発生した可能性がありますか?関数は外部プログラムの状態にとらわれずに動作できます
。– avgvstvs

775

私があなたの状況を正しく理解している場合、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()に値を割り当てる前にその値を読み取ると、UnboundLocalErrorPythonはすでにローカル変数である必要があると判断しているため、関連付けられている値はまだありません。しかし、 ' global'ステートメントを使用することで、ローカルに割り当てるのではなく、別の場所で名前を探すようにPythonに指示します。

(この動作は主にローカル名前空間の最適化によって発生したと思います-この動作がない場合、PythonのVMは関数内に新しい名前が割り当てられるたびに少なくとも3つの名前ルックアップを実行する必要があります(名前がtはすでにモジュール/ビルドレベルで存在します)、これは非常に一般的な操作を大幅に遅くします。)


名前空間の決定はコンパイル時に行われるとおっしゃいましたが、私はそれが本当だとは思いません。私はPythonのコンパイル学んだことから、構文エラーのためにのみチェックを、名前ではなくエラーこの例でみてくださいデフA():X + = 1、あなたはそれを実行しない場合、それはなりUnboundLocalErrorを与えていない、確認してくださいありがとう
watashiSHUN

1
次のようなグローバル変数には大文字を使用するのが一般的ですMyGlobal = 5
Vassilis

3
@watashiSHUN:名前空間の決定コンパイル時に行われます。それxがローカルであると判断することは、ローカル名が最初に使用される前に値にバインドされているかどうかを実行時にチェックすることとは異なります。
BlackJack

9
@Vassilis:すべての文字を大文字にするのが一般的ですMY_GLOBAL = 5Pythonコードのスタイルガイドを参照してください。
BlackJack

223

名前空間の概念を調べてみてください。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

1
理由がわからないので、config.x 取り除くことができますか?私が付いてきてx = lambda: config.x、それからに新しい価値が生まれましたx()。どういうわけか、持っていることa = config.xは私にとってトリックをしません。
vladosaurus

3
@vladosaurusはそれを from config import x解決しますか?
jhylands 2018

93

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変数であることを確認してください。


12
ヒューリスティックはバインディング操作を探します。割り当てはそのような操作の1つであり、別の操作をインポートします。しかし、forループのターゲットと、asin withおよびexceptステートメントの後の名前もバインドされます。
Martijn Pieters

後の名前のために@MartijnPieters asexcept、これは私には明らかではなかった句。ただし、メモリを節約するために自動削除されます。
ロバート

1
@Robert:メモリを節約するのではなく、循環参照の作成を回避します。これにより、メモリリークが発生する可能性があります。これは、例外がトレースバックを参照し、トレースバックas ...が、例外ハンドラーのターゲットを含む、コールスタック全体に沿ったすべてのローカルおよびグローバル名前空間を参照するためです。
Martijn Pieters

62

関数でグローバル変数を参照する場合は、globalキーワードを使用して、どの変数がグローバルであるかを宣言できます。すべてのケースでこれを使用する必要はありません(ここで誰かが誤って主張しているように)-式で参照されている名前がローカルスコープまたはこの関数が定義されている関数のスコープで見つからない場合、グローバルから検索されます変数。

ただし、関数でグローバルとして宣言されていない新しい変数に割り当てると、その変数は暗黙的にローカルとして宣言され、同じ名前の既存のグローバル変数に影を付ける可能性があります。

また、グローバル変数は、特にOOPがやりすぎである小さなスクリプトの場合、そうでないと主張する一部のOOP熱狂者とは異なり、有用です。


絶対に。狂信者。ほとんどのPythonユーザーはそれをスクリプトに使用し、小さなコードを分離するための小さな関数を作成します。
Paul Uszak

51

ある関数でグローバル変数を作成した場合、その変数を別の関数でどのように使用できますか?

次の関数を使用してグローバルを作成できます。

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)である可能性があります。


クールですが、クラス内の関数内にグローバル変数を作成し、別のクラス内の別の関数内でその変数を使用したい場合はどうすればよいですか?
ちょっと

2
@anonmanxなぜあなたが行き詰まっているのかはわかりません。これは、メソッドでの動作が通常の関数の場合と同じです。しかし、私はあなたのコメントといくつかのデモコードで私の答えを更新します、よろしいですか?
アーロンホール

1
@anonmanxどうですか?
アーロンホール

わかった。そのため、そのグローバル変数を使用するには、その関数を明示的に呼び出す必要があります。
anonmanx

47

既存の回答に加えて、これをさらに混乱させる:

Pythonでは、関数内でのみ参照される変数は 暗黙的にグローバルです。変数に関数本体内のどこかに新しい値が割り当てられている場合、その変数はローカルであると見なされます。変数に関数内で新しい値が割り当てられる場合、変数は暗黙的にローカルであり、明示的に「グローバル」として宣言する必要があります。

最初は少し意外ですが、少し考えてみるとこれが説明されます。一方では、割り当てられた変数にグローバルを要求すると、意図しない副作用を防ぐことができます。一方、すべてのグローバル参照にグローバルが必要な場合は、常にグローバルを使用します。組み込み関数またはインポートされたモジュールのコンポーネントへのすべての参照をグローバルとして宣言する必要があります。この混乱は、副作用を特定するためのグローバル宣言の有用性を無効にします。

出典:Pythonのローカル変数とグローバル変数のルールは何ですか?


34

並列実行では、何が起こっているのか理解していない場合、グローバル変数が予期しない結果を引き起こす可能性があります。マルチプロセッシング内でグローバル変数を使用する例を次に示します。各プロセスが独自の変数のコピーで機能することがはっきりとわかります。

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]

25

あなたが言っているのは、このような方法を使うことです:

globvar = 5

def f():
    var = globvar
    print(var)

f()  # Prints 5

しかし、より良い方法は、次のようにグローバル変数を使用することです。

globavar = 5
def f():
    global globvar
    print(globvar)
f()   #prints 5

どちらも同じ出力になります。


25

結局のところ、答えは常に単純です。

以下は、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()

この単純なコードはそのように機能し、実行されます。お役に立てば幸いです。


1
おかげで、私はpythonが初めてですが、Javaについて少し知っています。あなたが言ったことは私のために働いた。そして、クラス内でglobal a <ENTER>を書くと、関数内で 'global a'を書くよりも意味が
わかりそうです。globala

2
これはおそらく、私にとって最もシンプルでありながら非常に便利なpythonトリックです。このモジュールに名前を付けて、起動スクリプトで呼び出されるでglobal_varsデータを初期化しますinit_global_vars。次に、定義されたグローバル変数ごとにアクセサーメソッドを作成します。私はこれを何度も賛成できることを願っています!ピーター、ありがとう!
swdev 2014

1
多くのグローバル変数があり、グローバルステートメントの後にそれらを1つずつリストする必要がない場合はどうなりますか?
jtlz2 2015

23

使用するすべての関数でグローバル変数を参照する必要があります。

次のように:

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]
"""

3
「使用するすべての関数で」は微妙に正しくないため、次の値に近いはずです。「更新するすべての関数で」
spazm

21

グローバルをローカル変数に実際に格納するのではなく、元のグローバル参照が参照するのと同じオブジェクトへのローカル参照を作成するだけです。Pythonのほとんどすべてがオブジェクトを参照する名前であり、通常の操作では何もコピーされないことに注意してください。

識別子が事前定義されたグローバルを参照する場合を明示的に指定する必要がなかった場合、おそらく代わりに識別子が新しいローカル変数である場合を明示的に指定する必要があります(たとえば、 'var'コマンドのようなもので) JavaScriptで見られます)。重大で自明ではないシステムでは、ローカル変数がグローバル変数よりも一般的であるため、ほとんどの場合、Pythonのシステムの方が理にかなっています。

あなたは可能性があり、それが存在していたか、それがなかった場合は、ローカル変数を作成する場合は、グローバル変数を使用して、推測しようとした言語を持っています。ただし、これはエラーが発生しやすくなります。たとえば、別のモジュールをインポートすると、その名前のグローバル変数が誤って導入され、プログラムの動作が変更される可能性があります。


17

これを試して:

def x1():
    global x
    x = 6

def x2():
    global x
    x = x+1
    print x

x = 5
x1()
x2()  # output --> 7


14

続いて、アドオンとして、ファイルを使用して、すべてローカルで宣言されたすべてのグローバル変数を格納し、次に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):

1
グローバル変数を別のファイルに移動する利点は何ですか?小さなファイルにグローバル変数をグループ化するだけですか?そして、なぜステートメントを使用するのimport ... as ...ですか?なぜimport ...ですか?
olibre

1
ああ...私は最終的に利点を理解しました:キーワードを使用する必要はありませんglobal:-) => +1 :-)他の人々が持っているかもしれないこれらの尋問を明確にするためにあなたの答えを編集してください。乾杯
-olibre

13

グローバル配列の明示的な要素への書き込みは、グローバル宣言を必要としないようですが、「卸売」への書き込みには次の要件があります。

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

7

他のどの回答でも見たことがないので、これを追加します。似たような問題に苦しんでいる人にとっては役立つかもしれません。この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のみであることを確認してください。


3
globals()常にローカルコンテキストで使用可能なグローバルを返すため、ここでの変更は別のモジュールに反映されない場合があります。
キランジョナラガッダ

6

変更を表示するクラスの名前空間を参照します。

この例では、ランナーはファイル構成の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()

1

グローバルは問題ありません-マルチプロセッシングを除く

一方はWindows / Mac OS、もう一方はLinuxであるため、さまざまなプラットフォーム/環境でのマルチプロセッシングに関連するグローバルは面倒です。

これを、前に遭遇した問題を指摘する簡単な例で示します。

Windows / MacOと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

これをLinuxで実行すると、代わりに次のようになります。

task 0: counter = 1
task 1: counter = 1
task 2: counter = 1
task 3: counter = 1
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.