nonlocalの概要
Python
3で導入されたnonlocal
キーワードは、ネストされた関数内から外側の関数に定義された変数を操作するための仕組みを提供します。通常、ネストされた関数はその関数自身のローカルスコープで変数を作成しますが、nonlocal
を使うことで外側のスコープの変数にアクセスし、値を変更することができます。
これは、特にクロージャや状態を持つ関数(例えばカウンタ関数)を実装する際に非常に役立ちます。nonlocal
なしでは、内部関数から外部関数の変数を変更することはできません。
nonlocalの使用例
基本的な例
以下は、nonlocal
を使わない場合の例です。
def outer():
x = 1
def inner():
x = 2
print("inner:", x)
inner()
print("outer:", x)
outer()
結果は以下の通りです:
inner: 2
outer: 1
内部関数inner()
でx = 2
としていますが、これはinner()
内部のx
を変更しただけであり、outer()
のx
には影響を与えていません。
これに対して、nonlocal
を使用すると以下のように動作が変わります。
def outer():
x = 1
def inner():
nonlocal x
x = 2
print("inner:", x)
inner()
print("outer:", x)
outer()
結果:
inner: 2
outer: 2
このように、nonlocal
を使うと、inner()
内で外部関数outer()
のx
を変更することが可能になります。
globalとの違い
nonlocal
はglobal
キーワードと似た機能を持ちますが、その適用範囲が異なります。global
はモジュール全体で定義された変数を操作するのに対し、nonlocal
は外部関数のスコープに限定されます。
次のコードでその違いを確認できます。
x = 0
def outer():
x = 1
def inner():
global x
x = 2
print("inner:", x)
inner()
print("outer:", x)
outer()
print("global:", x)
結果は以下の通りです:
inner: 2
outer: 1
global: 2
この場合、global
を使うことでx
の変更がモジュール全体に影響しています。
nonlocalの適用範囲
nonlocal
はネストされた関数でのみ使用可能です。トップレベルの関数やグローバルスコープでは無効です。また、外側の関数で変数が定義されていない場合には、nonlocal
を使用するとエラーが発生します。以下の例ではエラーが発生します。
def outer():
def inner():
nonlocal x # エラー: xの外側スコープが見つからない
x = 2
inner()
outer()
nonlocal
を使うためには、必ず外側のスコープに対象となる変数が存在している必要があります。
よくある使用例
nonlocal
は、クロージャやカウンタのような状態を保持する関数を実装する際によく使用されます。以下はその一例です。
def make_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
counter = make_counter()
print(counter()) # 1
print(counter()) # 2
print(counter()) # 3
この例では、nonlocal
を使ってカウンタの状態count
を外側のスコープで保持しています。
まとめ
Python
のnonlocal
キーワードは、ネストされた関数内で外側のスコープの変数を変更する便利な手段です。global
とは異なり、モジュールのグローバルスコープにアクセスするのではなく、外側の関数スコープにのみ影響を与えます。クロージャや状態を持つ関数を作成する際に非常に有用です。