変数のスコープ(scope)とは、その変数がアクセス可能なコンテキストのことです。Pythonには覚えやすいLEGBの原則に基づく4つの基本的なスコープがあります。
globalキーワードは、関数内からグローバルスコープで定義された変数を変更することを可能にします。
def foo(): global my_var my_var = 10 # グローバル変数を変更
関数内でglobalを使わないと、変数はローカルと見なされ、外側のスコープに同名の変数があっても影響しません。
"次のコードは何を出力しますか?"
x = 10 def func(): x = 20 func() print(x)
答え:
10が出力されます。なぜなら、関数内で新しいローカル変数xが作成されるため、グローバルな変数は変更されません。
ストーリー
ボットのコマンドハンドラーでグローバルカウンターを保持したいが、globalを忘れました:
counter = 0 def increment(): counter += 1 # UnboundLocalError: local variable 'counter' referenced before assignment
これは、インタプリタがcounterをローカル変数と見なしているため(関数内で代入が行われるため)、グローバル変数と見なされません。
ストーリー
ネストされた関数でnonlocalキーワードを忘れてしまったため、隠された変数がローカルスコープを作成しました:
def outer(): x = 0 def inner(): x += 1 # UnboundLocalError、xはinner内でローカルと見なされる
正しい形:
def outer(): x = 0 def inner(): nonlocal x x += 1
ストーリー
ワンライナーを書いていました:
x = 5 y = (lambda: (x := x + 1))() # Python < 3.8ではSyntaxError、または後でUnboundLocalError
expressionとlambdaのスコープの違いを忘れていました。すべての構文がlambda内での代入をサポートするわけではなく、Pythonのバージョンによって異なります。