変数のスコープ(グローバル変数とローカル変数)

当サイトではアフィリエイトプログラムを利用して商品を紹介しています。

グローバルスコープとローカルスコープ

Pythonの変数は定義する場所によって読み書きできる範囲が決まります。
この範囲のことを変数のスコープとよびます。
スコープ(scope)とは日本語で「可視範囲」を意味します。 

グローバルスコープ

関数またはクラスの外で変数を定義すると、その変数はグローバルスコープに定義されたことになり、プログラム内のどこからでも読み書きすることができます。このような変数をグローバル変数とよびます。

# PYTHON_GLOBAL_SCOPE

# In[1]

# グローバル変数を定義
x = 100

# グローバル変数は関数内部から読み込むことができます
def my_func1():
    return x

my_func1()
# 100

上のサンプルコードではグローバルスコープに変数 x を定義して、それを関数内部から読み込んで値をそのまま返しています。
 
次はグローバル変数を関数内部から書き換えてみます。

# In[2]

# グローバル変数を定義
y = 100

# グローバル変数を関数内部で書き換えます
def my_func2():
    y = y + 1
    return y

my_func2()

'''
UnboundLocalError
 Traceback (most recent call last)
 <ipython-input-2-0bd57360a01e> in <module>()
      7     return y
      8
 ----> 9 my_func2()

 <ipython-input-2-0bd57360a01e> in my_func2()
      4 # グローバル変数を関数内部で書き換えます
      5 def my_func2():
 ----> 6     y = y + 1
      7     return y
      8
 UnboundLocalError: local variable 'y' referenced before assignment
'''

エラーが表示されました。関数内部から書き込む場合には global というキーワードを添えて、それがグローバル変数であることを明示しなくてはなりません。正しいコードは次のようになります。

# In[3]

# グローバル変数を定義
y = 100

# グローバル変数を関数内部で書き換えます
def my_func2():
  #グローバル変数であることを明示
    global y
    y = y + 1
    return y

my_func2()
# 101

関数内部からの書込みに関して、このような手続きが定められているのは、基本的にグローバル変数を関数内部から書き換えることは好ましくないとされているからです(そんなことをするメリットもないはずです)。ここではグローバル変数がどこからでも読み書きできるという性質をもつことを説明するために、敢えて上のようなコードを書きましたが、よほどの理由がない限りは、このような関数は作らないでください。関数と内と外はなるべく分離されていたほうがメリットが大きいのです。

ローカルスコープ

関数内部で変数を定義すると、その変数はローカルスコープに定義されたことになります。このような変数はローカル変数とよばれ、外部からアクセスできないようになっています。
 
試しに関数内部でローカル変数を定義して、外部からのアクセスを試みてみます。

# PYTHON_LOCAL_SCOPE

# In[1]

def my_func3():
    #ローカル変数を定義
    z = 100
    return z

# ローカル変数に外部からアクセスを試みます
print(z)

'''
NameError
 Traceback (most recent call last)
  in ()
      3     return z
      4 
 ----> 5 print(z)
 NameError: name 'z' is not defined
'''

“z is not defined (z は定義されていません)” というエラーメッセージが表示されました。つまりローカル変数 z は、関数の外側ではまったく存在しないも同然ということです。
 
ローカル変数はグローバル変数と同じ名前で定義することができます。

# In[2]

# グローバル変数を定義
w = 10

def my_func4():
    # ローカル変数を定義
    w = 20
    return w

print(w, my_func4())
# 10 20

w と my_func4() の値を並べて表示させています。グローバル変数 w は値を変えずに、そのままの状態が保持されています。関数はその内側で定義した w = 20 を返しています。この2つの変数 w は名前が同じであっても、まったく別の変数であることを示しています。

これが変数のスコープを定めるメリットです。
もし変数にスコープという仕組みがなかったら、関数内部で変数を定義するときに、変数名がすでにグローバル変数として使用されたものでないか、いつも気にしなければなりません。同じ名前を使ってしまうと、関数を使うことによってグローバル変数が書き換えられ、場合によってはプログラムが破壊されてしまうことになるからです。プログラムの規模が大きければ大きいほど、その危険性は増します。しかし関数の内側と外側が分離されていれば、プログラマは変数名の衝突に怯えることなく、のびのびと関数を作ることができます。

コメント

  1. あとりえこばと より:

    【プログラミング日記】こんな仕事をしていれば、1日にものすごい数のキータッチをするわけで、すでに左右の人差し指がやられています(慢性的に腱鞘炎状態です)。このまえ、マウスでクリックしようと思ったら、指がぶるぶると震えて思うように動かせなくなっていました。我ながら「これはやばい」と思いましたね(←相当ヤバいでしょ)。叔父夫婦が腱鞘炎に効く塗り薬と湿布を送ってくれました(つい先ほど届いたばかりです)。本当にありがたいです。

    もともと私はキーを強く叩きすぎる癖があるので、それを治す必要があるようです。そんなわけで、近頃は意識的にキーを柔らかくタッチするように心がけています。キーボードの上に指を滑らせるようにしながら最小限の力でキーを押す、という感じですね。長年の癖はなかなか抜けませんが、少しずつでも改善して行こうと思っています。

    しかし、よくよく考えてみると、こういう打ち方というのは、タッチタイピングの練習を始めたときに覚えるべきことなのかもしれません。しかし世間のタイピング教室では「いかに早く打つか」を教えても、「指に負担をかけないように、最小のエネルギーで打つ方法」は教えてくれません。音を立てて勢いよく「ダダダダッ」と打つのは、悪いお手本のように思えるのです。「無音」こそが究極のタイピングであるはずです。真の達人(ハイマスター)は一切音を立てないはずです(←本当か?)。私もいずれは「無音」の境地に達することを願いつつ、今日もキーを打ち続けるのです(←カチャカチャと音と立てながらこの文を書いている)。

  2. あとりえこばと より:

    【AI連載小説】羽村陽子のプログラミング日記(17)
     
    橋本のもと、新入社員の悠香はPythonの変数のスコープについて学ぶ日がやってきた。陽子も興味津々でその様子を見守っていた。橋本は微笑みながら悠香に語りかけた。「悠香さん、Pythonでプログラミングをする上で欠かせないのが変数のスコープです。変数がどこで有効か、どこからアクセスできるか、しっかり理解することが重要ですよ」
    悠香は橋本に向かって興味津々な目を輝かせ、
    「スコープって、どうしてそんなに重要なんですか?」
    と尋ねた。陽子も加わりながら、橋本は簡単なサンプルコードを使って説明を始めた。
    「スコープが明確でないと、例えば関数内で定義された変数が関数外で使えなかったり、逆に関数外で定義された変数が関数内で変更されてしまったりします」
    そして、Jupyter Notebook上に以下のコードを示した。

    # グローバルスコープの変数
    global_variable = "I'm global!"
    
    def example_function():
        # ローカルスコープの変数
        local_variable = "I'm local!"
        print(local_variable)
    
    example_function()
    print(global_variable)
    
    # エラーが発生する行
    # print(local_variable)

    陽子は悠香とともにコードを追いながら、
    「確かに、スコープが違うと変数の挙動も変わるんですね」
    とコメントした。橋本は優しく微笑みながら続けました。
    「スコープの理解が深まると、プログラムの動作をより細かく制御できます。悠香さんもどんどん試してみてください」
    こうして、新入社員悠香と陽子は変数のスコープについて学び、Pythonの奥深さに共に興奮を覚えていた。

    橋本は丁寧に説明を進めながら、
    「変数のスコープには、大きく分けてローカルスコープ、エンクロージングスコープ、グローバルスコープ、ビルトインスコープといった種類があります。それぞれのスコープがどのような範囲を持ち、どのように変数がアクセスされるか理解することが肝要です」
    と語りかけました。橋本はデモンストレーションとして以下のようなコードを示しました。

    # グローバルスコープ
    global_variable = "I'm global!"
    
    def outer_function():
        # エンクロージングスコープ
        outer_variable = "I'm in the outer function!"
    
        def inner_function():
            # ローカルスコープ
            local_variable = "I'm in the inner function!"
            print(local_variable, outer_variable, global_variable)
    
        inner_function()
    
    outer_function()
    
    # エラーが発生する行
    # print(local_variable, outer_variable)

    悠香は興味津々でコードを追いながら、
    「なるほど、スコープが入れ子になると、変数のアクセス範囲も変わるんですね」
    とコメントしました。陽子も頷きながら、
    「これで関数やクラスを書く上で、変数の挙動がより予測可能になりそうですね。」
    と感想を述べました。橋本は微笑みながら、
    「正確なスコープの理解は、プログラムのバグを減少させ、効率的なコードを書く手助けになります。悠香さん、陽子さん、どんどん質問してみてくださいね」
    と励ましました。