Python bite: グローバル変数へのアクセス
Tagged:

以下の Python コードでは、 関数 multiply はグローバル変数 var を引数 x 倍したものを返します。

var = 10

def multiply(x):
    return (var * x)
グローバル変数の参照

このコードをもって、 関数から大域変数に「アクセスできる」と思っていると咬まれます

以下のようなコードで、 multiply() 起動毎にグローバル変数 varx 倍しようと思っても、 期待通りには動いてくれません。

% cat multiply.py
var = 10

def multiply(x):
    var *= x

multiply(10)
print var
% python multiply.py
Traceback (most recent call last):
  File "./multiply.py", line 6, in ?
    multiply(10)
  File "./multiply.py", line 4, in multiply
    var *= x
UnboundLocalError:
  local variable 'var' referenced before assignment
グローバル変数への代入 ~ 失敗

Python における名前解決は、 参照の際にはローカルからグローバルまでの全てのスコープで解決が試みられますが、 代入の際にはローカルスコープでしか名前解決が行われません (それ以外のスコープは読み出し専用)。

グローバルスコープでの名前解決を行いたい場合には、 変数に対する global 宣言が必要になります。

% cat multiply.py
var = 10

def multiply(x):
    global var
    var *= x

multiply(10)
print var
% python multiply.py
100
グローバル変数への代入 ~ 成功

これについては、 Python リファレンスマニュアルの "名前づけと束縛"や、 Python チュートリアルの "Python のスコープと名前空間"、 オライリーの "初めてのPython" など、 多くの場所で言及されています。 私自身も Python を修得する際にこの仕様を見て、「PHP っぽいなぁ」と思った記憶があります。

しかし、 グローバル変数そのものが読み出し専用であっても、 グローバル変数が保持するオブジェクトがリストやマップだったりすると、 オブジェクト内容の変更そのものは可能、 という振る舞いをするため、 ついつい global のことを忘れてしまうのも良くないのでしょう。