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

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

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

 変数 は定義する場所によって読み書きできる範囲が決まります。
 この範囲のことを 変数のスコープ (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)
  in ()
      7     return y
      8
 ----> 9 my_func2()

  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 は名前が同じであっても、まったく別の変数であることを示しています。

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