概要
グローバル変数を使っていたところUnboundLocalError
が発生しました。
ドキュメントにも書いてあることなのですが、改めて簡単にPythonのスコープを検証してみます。
環境
Python3.12
UnboundLocalErrorが発生するコードとハマった原因
val = 0
def f():
val += 1 # UnboundLocalErrorになる
print(f"f scope: val = {val}")
f()
これをそのまま実行するとUnboundLocalError: cannot access local variable 'val' where it is not associated with a value
のようにエラーとなります。
このコードを書いたときの思考としては
-
val = 0
はグローバルで宣言している - 関数内でも
val
は使える - なら
val
の値も更新できる
でした。
特に最後のval
の値を更新できるというのが間違っていました。
Pythonにおいて関数の外で宣言された変数(ここでいうval
)は、参照しかされなければグローバル変数として振る舞います。ただし、値が代入された場合ローカル変数になります。
ややこしいのはval += 1
が一見すると実行できそうに見えることです。
書き換えてみればわかりますが、val += 1
は
val = 0
def f():
val = val + 1
print(f"f scope: val = {val}")
f()
のようになります。
val = val + 1
でval
へ代入しているためローカル変数として扱われます。
そしてローカル変数であるval
が関数内で宣言されていないためにUnboundLocalError
が発生するのです。
グローバル変数として明示的に扱う
解決策は簡単でglobal
を変数の前につけます。
val = 0
def f():
global val
val += 1
print(f"f scope: val = {val}")
f()
このようにするとval
をグローバル変数として扱うためval += 1
が通ります。