グローバルスコープとローカルスコープ
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日にものすごい数のキータッチをするわけで、すでに左右の人差し指がやられています(慢性的に腱鞘炎状態です)。このまえ、マウスでクリックしようと思ったら、指がぶるぶると震えて思うように動かせなくなっていました。我ながら「これはやばい」と思いましたね(←相当ヤバいでしょ)。叔父夫婦が腱鞘炎に効く塗り薬と湿布を送ってくれました(つい先ほど届いたばかりです)。本当にありがたいです。
もともと私はキーを強く叩きすぎる癖があるので、それを治す必要があるようです。そんなわけで、近頃は意識的にキーを柔らかくタッチするように心がけています。キーボードの上に指を滑らせるようにしながら最小限の力でキーを押す、という感じですね。長年の癖はなかなか抜けませんが、少しずつでも改善して行こうと思っています。
しかし、よくよく考えてみると、こういう打ち方というのは、タッチタイピングの練習を始めたときに覚えるべきことなのかもしれません。しかし世間のタイピング教室では「いかに早く打つか」を教えても、「指に負担をかけないように、最小のエネルギーで打つ方法」は教えてくれません。音を立てて勢いよく「ダダダダッ」と打つのは、悪いお手本のように思えるのです。「無音」こそが究極のタイピングであるはずです。真の達人(ハイマスター)は一切音を立てないはずです(←本当か?)。私もいずれは「無音」の境地に達することを願いつつ、今日もキーを打ち続けるのです(←カチャカチャと音と立てながらこの文を書いている)。