ユーニックス総合研究所

  • home
  • archives
  • python-global-variable

Pythonのグローバル変数の使い方【global】

  • 作成日: 2023-12-26
  • 更新日: 2023-12-26
  • カテゴリ: Python

Pythonのグローバル変数はどう使う?

グローバル変数とはコードにおいてグローバルな領域に宣言される変数のことを言います。
このような変数はグローバル変数と呼ばれ、いっぽうグローバルでないローカルな変数はローカル変数と呼ばれます。

コードにしてみるとこれの違いは明確です。

# グローバル変数  
global_var = 'Hello'  

def main():  
    # ローカル変数  
    local_var = 'World'  

この記事ではPythonでグローバル変数を扱う方法を解説します。

関連記事
Pythonのglobal宣言文の使い方と構造

Pythonにおけるグローバル変数とは何か?

Pythonにおけるグローバル変数とはなんでしょうか?
たとえばmain.pyというファイルを作ったとします。
そしてこのファイルに以下のような変数を定義しました。

# グローバル変数  
one = 1  
two = 2  
three = 3  

このような変数はすべてグローバル変数と呼ばれます。
つまり上記のone, two, threeはすべてグローバル変数です。

Pythonにおけるローカル変数とは何か?

ではローカル変数とは何になるのか?
変数を定義しただけでグローバル変数になるのであれば、ローカル変数などないのではないか?
ということなんですが、これはたとえば関数内の変数がローカル変数に当たります。

def main():  
    four = 4  
    five = 5  
    six = 6  

上記のfour, five, sixはすべてローカル変数であり、グローバル変数ではありません。

グローバル変数はファイルの一番外側にべた書きされている変数で、ローカル変数は関数の中の変数。
という風に覚えておけばいいと思います。

Pythonでグローバル変数を参照する

Pythonでグローバル変数を使いたい場合は以下のようにグローバル変数を参照します。

one = 1  

print(one)  # 1  

また関数内からグローバル変数を参照したい時もあります。

one = 1  

def main():  
    print(one)  # 1  

上記のようにすればグローバル変数は参照できます。

グローバル変数が参照できない?

少し込み入ったコードではグローバル変数が参照できない時があります。
たとえば以下のようなコードです。

d = {'one': 1}  

def main():  
    d = {}  
    def sub():  
        print(d['one'])  
        # KeyError: 'one'  

    sub()  

main()  

グローバル変数としてd = {'one': 1}を定義しています。
そしてmain関数内ではd = {}でローカル変数を。
そしてsub関数内ではprint(d['one'])dを参照しています。

しかしこのコードを実行すると、print(d['one'])でエラーになります。
sub関数内でdを参照してこれはグローバルのdだと期待しますが、実際にはmain関数内のdが参照されてしまっています。

この場合は後述するglobal文を使うことで解決できます。
以下はglobal文で解決しているコードです。

d = {'one': 1}  

def main():  
    d = {}  
    def sub():  
        global d  
        print(d['one'])  # 1  

    sub()  

main()  

Pythonでグローバル変数を変更する

グローバル変数を変更する場合は注意が必要です。
グローバルスコープ、つまりグローバルな領域でグローバル変数を変更する場合は以下のように変更できます。

one = 1  
print(one)  # 1  

one = 2  
print(one)  # 2  

しかし関数内からグローバル変数を変更しようとした場合ですが、以下の動作を見てください。

one = 1  

def main():  
    one = 2  
    print(one)  # 2  

main()  
print(one)  # 1  

上記のコードで注目してほしいのが、main関数を呼び出した後の変数oneの値です。
main関数の中でone2に変更しています。これは成功しているように見えます。
しかしmain関数を呼び出し終わって、oneを出力すると1のままです。

main関数内でoneを変更しているのに、なぜmain関数が終わったら変更されないままになっているのでしょうか?
実はこれはPythonの言語仕様によるもので、Pythonではone = 2というのがグローバル変数への代入なのか、それともローカル変数として新しく定義しているのか、というのが判断が付かないのです。
ですのでこの場合は、Pythonはローカル変数の定義として処理します。

つまり

def main():  
    one = 2  
    print(one)  # 2  

上記のone = 2oneはmain関数内のローカル変数になっているわけですね。
これを確認するにはid()でオブジェクトのアイデンティティーを確認します。
オブジェクトのアイデンティティーとはオブジェクトに割り振られる一意に決まるナンバーのことです。

one = 1  
print(id(one))  
# 140710367270672  

def main():  
    one = 2  
    print(id(one))  
    # 140710367270704  

main()  
print(id(one))  
# 140710367270672  

上記のコードを見ますと、main関数内のoneだけアイデンティティーが異なっているのがわかります。
これはmain関数内のoneがグローバル変数のoneとは違うオブジェクトであることを表しています。
プログラマーはoneをグローバル変数だと思って変更するわけですが、実際にはローカル変数になっているということです。

global文

この問題を解決するにはglobal文を使います。

関連記事
Pythonのglobal宣言文の使い方と構造

global文 — Python 3.12.1 ドキュメント

このglobal文で変数を宣言するとPythonはその宣言された変数をグローバル変数として扱います。
ですのでmain関数内のoneをglobal文で宣言すればそれはグローバル変数として処理されます。

one = 1  

def main():  
    global one  
    one = 2  
    print(one)  # 2  

main()  
print(one)  # 2  

上記のコードではmain関数内でoneをグローバル宣言しています。
よってmain関数内のoneはグローバル変数だとPythonは解釈します。
そのあとにone = 2で変数の値を変更しています。

main関数の呼び出し後にoneを参照すると、ちゃんと値が変更されているのがわかります。

global文の文法

global文の文法は以下のようになっています。

global_stmt ::= "global" identifier ("," identifier)*  

この文法の記法はBNF(バッカス・ナウア記法)と呼ばれるものです。
プログラミング言語の開発などで使われる言語の設計を記述する記法です。

上記のBNFを見ますと、global_stmt(グローバル文)は

"global" identifier ("," identifier)*  

という中身になっています。
まず最初にglobalというキーワードが入り、そのあとにidentifier(識別子)が書かれます。
識別子は変数などのことです。
そしてカンマ(,)で区切られてさらにidentifierが0個以上書けるようになっています。

この文法を参考にすると以下のコードが合法になります。

global one  
global one, two  
global one, two, three  

global文はPythonのパーサーに対する指示句(directive)になっています。
この指示句はglobal文と同時に読み込まれたコードに対してのみ有効です。

別ファイルのグローバル変数を参照する

別ファイルのグローバル変数を参照するにはどうしたらいいでしょうか?
たとえば以下のようなsub.pyというファイルがあります。

hello = 'Hello'  

このsub.pyのグローバル変数であるhellomain.py内で参照するにはどうしたらいいのか?
この場合は以下のように参照します。

import sub  

print(sub.hello)  # Hello  

from sub import hello  

print(hello)  # Hello  

import subのようにsub.pyをインポートして、ドット演算子でsub.helloのように参照できます。
またfrom sub import helloのようにすれば、helloを参照することができます。

グローバル変数の命名規則

グローバル変数の命名規則ですが、これはプロジェクトによってコーディングルールが変わりますので、一概にこうしろとは言えません。
慣例的には変数の接頭辞(プリフィックス)にg_を付けることが多いようです。
gglobalgです。

g_hello = 'Hello'  
gWorld = 'World'  

なぜこのようなプリフィックスを必要とするのかと言うと、グローバル変数はどこからでも参照できるため、スコープが区切られていません。
区切られているとしたらモジュール単位です。
ですので、どこからでも参照できてしまう変数がよく使われる名前になっていると、紛らわしいことがあります。
よってg_などのプリフィックスを付けることがあります。

グローバル変数の初期化

グローバル変数の初期化は関数としてできるようにしておくと、初期化処理などが走ったときにその関数を呼び出すだけで済みます。
たとえばinit_globals()という関数を作ってグローバル変数を初期化します。

one = 1  
two = 2  

def init_globals():  
    global one, two  
    one = 1  
    two = 2  

one = 10  
two = 20  
init_globals()  
print(one, two)  # 1 2  

グローバル変数は避けるべきか?

一般的にはグローバル変数は開発では避けた方がいいと言われることが多いです。
グローバル変数はスコープが広大なため、いろいろなコードに影響を与える恐れがあるからです。
グローバル変数は使わない、という開発者の人も多いかと思います。

Pythonにはクラスがありますので、クラスのインスタンス変数として変数を定義すれば、そのインスタンス変数をクラス内のグローバル変数のように使えます。
よってクラスを作るのがPython的には便利かもしれません。

しかしクラスが無い言語では、たとえばC言語などではグローバル変数は多用されることがあります。
これはファイルをクラスと見立てて、グローバル変数をインスタンス変数かのように使い、関数をメソッドのように使うという感じです。
実際はファイルはクラスではなくインスタンスも生成されないため、クラスとは違うのですがC言語などは古の時代からこのような設計がよく行われていました。

そのためグローバル変数も使いようによっては便利、と言えるかもしれないので一概にグローバル変数は悪だ、ということは難しいと思います。

関連記事
Djangoでオブジェクトを一括作成・更新【bulk_create, bulk_update】
DjangoのModel.objects.filter()の使い方【QuerySet】
Djangoのmodelのcreate()の使い方【Python】
Django入門: ルートの設定 ~ 簡単な一行掲示板アプリを作る その4【Windows10】
NumPyのappend()の使い方: 配列の末尾に要素を追加
Numpyのarangeの使い方: 指定範囲の数列を生成する
Python3でYoutube Data APIを使ってキーワード検索する
PythonからC言語(my.puts)を呼び出して実行する