Python の Global 変数(の使い方と挙動について,纏めてみた.
グローバル変数の使い方
そもそもグローバル変数とは,プログラム内にて複数の関数が共通して使うことのできる変数.
あまりよく分からないという方は,挙動をみてからの方が理解しやすいでしょう.
関数の外側で定義したものはグローバル変数となり,関数内からグローバル変数にアクセスする場合は「これはグローバル変数だ」と宣言します.
グローバル変数は以下のように宣言します.
global 変数名
関数の外側にて,グローバル変数 a を宣言し,関数 add_func 内からアクセスする場合は以下のようになります.
a=0 #グローバル変数
def add_func(x):
global a
a+=x
add_func は x を引数に取り,a に x を足し合わせる関数です.
x=4 として関数を呼び出す前と後での a の変化を見てみます.
a=0
def add_func(x):
global a
a+=x
print(a) # 0
add_func(4)
print(a) # 4
a は最初 0 で初期化しているので,最初の print 文では 0 が出力されます.
その後 add_func(4) で 4 を足す操作をすることで,2回目の print 文では 4 が出力されます.
まあ,基本的にはこれだけではあるのですが,ここからは色々な挙動を見て性質を理解してみます.
関数内からの参照とローカル変数との違い
変数を操作するには,グローバル宣言が必要ですが,参照するだけなら特に宣言は必要ありません.
b = 134
def print_b():
print(b)
print_b() #134
print_b() は単純に b という名前の変数をプリントするという関数ですが,グローバル変数 b がプリントされます.
グローバル変数 b は 134 で初期化されてるので,関数 print_b() を呼び出すと 134 がプリントされます.
同様な,少し違う例だと..
b = 134
def calc_c():
c = b +16
print(c)
calc_c() # 150
print(c) # NameError:name 'c' is not defined
calc_c() は関数内でローカル変数 c を定義して,それをプリントする関数です.
ローカル変数 c は,b という名前の何かしらの変数を参照し,それに 16 を足した値で定義されます.
ここでは,グローバル変数 b の 134 が参照され,それに 16 を足した 150 が ローカル変数 c となり,プリントされます.
c はローカル変数なので,当然,プリントしようとしても未定義だというエラーが出ます.
では,関数内でグローバル変数と同じ名前のローカル変数を定義するとどうなるでしょうか.
b = 134
def print_b():
b = 1566
print(b)
print_b() #1566
print(b) #134
print_b() は,関数内で,ローカル変数 b を定義して,b という変数をプリントする関数です.
print_b() を呼ぶと,「1566」 がプリントされます.
これは,同じ名前の グローバル変数 b が元々「134」と定義されていますが,ローカル変数 b の方が参照されてプリントされているということです.
関数外で print(b) とすると,グローバル変数 b が参照され,グローバル変数 b には何も操作が加えられていないので,初期化した値の「134」がプリントされます.
では,このようにするとどうでしょうか.先の関数 print_b() 内の 1 行目と 2 行目を入れ替えただけの場合です.
b =134
def print_b():
print(b) # Error箇所
b = 1566
print_b() # UnboundLocalError: local variable 'b' referenced before assignment
print(b)
print_b() という関数は,まずグローバル変数 b をプリントしたのち,ローカル変数 b を「1566」で初期化する,と読めます.
このように,同じ名前のグローバル変数とローカル変数が混在する関数を呼ぶとエラーが出てしまいます.
「 local variable 'b' referenced before assignment 」,「ローカル変数 b が定義される前に参照されている」ということ.
エラーになる理由は以下のような感じ.
関数 print_b() が定義された時点で「b = 1566」という一行があることで, print_b() 内では「b という変数はローカル変数として扱う」とされるのです.
そして,print_b() を呼び出すと,まず最初に print(b) つまり,「ローカル変数 b をプリントしてくれ」という指示がきます.
変数 b は,確かにこの変数内では「ローカル変数として扱われる」ことだけは決定していますが,まだその詳細は定義されていません.
なので,それをプリントしろという指示に対しては「ローカル変数 b が定義される前に参照されている」というエラーが吐かれるのです.
あまり内部処理に詳しいわけではないのですが,「b = 1566」という一行のようにローカル変数たらしめる操作があることで,関数が定義された時点で,それはローカル変数となるみたいですね.
逆に関数内で一度でもグローバル宣言を行えば,その関数内では全てグローバル変数として扱われます.
例をあげると
u=0
def plus(x):
if x==1:
global u
u+=1
elif x==2:
u+=2
else:
print(u)
グローバル変数 u に,引数 x が 1 か 2 なら,1 または 2 を足す,それ以外の引数の時は 変数 u をプリント,という関数 plus(x)
一見,一つ目の条件分岐のみでしかグローバル宣言されていないように見えますが,関数全体でグローバル宣言されていることになります.
この関数を定義した上で,plus(2),plus(5) と順に呼び出すと,
plus(2)
plus(5) # 2
print(u) # 2
という結果に.plus(2) でグローバル変数 u = 0 に 2 が足され,plus(5) でグローバル変数 u がプリントされます.
もう一度確認のために,print(u) をすると,グローバル変数 u にしっかりと 2 が足される操作がされていたことがわかります.
一見,グローバル宣言がされている一つ目の条件分岐を通らなくとも,u は関数内でグローバル変数として扱われていることになります.
では,今度は,2番目の条件分岐でグローバル宣言するとどうなるか.
u=0
def plus(x):
if x==1:
u+=1
elif x==2:
global u
u+=2
SyntaxError: name 'u' is assigned to before global declaration
これは関数の定義時にエラーが出ます.「name 'u' is assigned to before global declaration」,つまり,「変数 u がグローバル宣言される前に,(ローカル変数っぽく) 割り当てられてますよ」といったエラー.
詳しい内部処理はわかりませんが,plus() という関数定義時にまず,上から順に読んでるのでしょう,
その際まず,「u+=1」という行が読まれます.これにより,「u はローカル変数っぽいな」という判断がなされます.
その後,「global u」という一行により,「あれ?ローカルじゃなかったん?」というエラーが「name 'u' is assigned to before global declaration」なんだと思います.
先の,一つ目の条件分岐にグローバル宣言があった例では,関数定義時にコンパイラが上から順に読み,「global u」があったその時点で,条件分岐とかも関係なしに,その関数内では「uはグローバル変数だ」という処理になるのだと思います.
つまり,条件分岐を入れようとも,関数内で同じ名前のローカル変数とグローバル変数は共存出来ないのです.
まとめ
基本的なグローバル変数の使い方を紹介しました.
その後挙動に関して見てみました.
関数内で同じ名前のローカル変数とグローバル変数は共存出来ないということをみました.
この判断基準は,関数を定義時に上から一行ずつ読み,ローカル変数たらしめる操作が先にあった場合,その関数内ではローカル変数に.
グローバル宣言が先にあった場合は,その関数内ではグローバル変数として扱われるのです.
拙い,かつ,当たり前のようなことを纏めてみましたが,自分自身はグローバル変数をより理解する機会となりました.