はてブロ@ama_ch

https://twitter.com/ama_ch

Pythonで関数内からグローバルスコープ変数へアクセスする場合

スコープ関係で悩んだのでメモメモ。
Pythonでは*1、関数内からグローバル変数を参照することができます。

参照
>>> a = 3    # グローバル変数
>>> def test1():
...     print a
... 
>>> test1()
3

関数内からグローバル変数を参照・表示していることがわかります。

代入
>>> a = 3    # グローバル変数
>>> def test2():
...     a = 10
...     print a
... 
>>> test2()
10

グローバル変数への代入ができましたできていません。
※追記※
コメントで指摘を頂きましたが、この関数test2での変数aはローカル変数です。以下を見て頂くと分かりやすいかと。

>>> a = 3    # グローバル変数
>>> def test2():
...     a = 10
...     print a
... 
>>> test2()
10
>>> a
3

このように、関数実行後にグローバル変数aを呼び出すと、何も変化していないことが分かります。
グローバル変数は関数から参照はできますが、代入はできないようです。

参照→代入
>>> a = 3    # グローバル変数
>>> def test3():
...     print a    # 参照
...     a = 10     # 代入
... 
>>> test3()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in test3
UnboundLocalError: local variable 'a' referenced before assignment

これだとエラーになります。
今回の処理の流れは以下

  1. グローバル変数aが存在する
  2. 関数内でaを参照する
  3. aに値を代入する

このとき、2ではグローバル変数のaが参照されますが、3ではローカル変数の扱いになるみたいです。
エラーも「そんな変数ねーよ!」って内容だし。


つまり、
関数内でグローバル変数の参照・代入は同時にできない
ということになります。

解決方法

global宣言を使います。

>>> a = 3    # グローバル変数
>>> def test4():
...     global a    # global宣言
...     print a     # 参照
...     a = 10      # 代入
... 
>>> test4()
3
>>> a
10

関数の先頭にglobal宣言がついた以外は、先程のものとまったく同じです。
ちゃんと参照と代入が両方ともできていますね。

ただし

スパゲッティコードのもとになりやすいので注意が必要です。
今書いてるコードが既に美味しいパスタ><

*1:他の言語でも大体当てはまると思うけど。