概要
グローバル変数を使っていたところ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が通ります。