この記事では、Pythonの関数内の関数である「内部関数」とそれを応用した「クロージャ」について解説します。
クロージャを使うことで関数で宣言された変数や受け取った引数を記憶することができます。
それでは、内部関数やクロージャについて見ていきましょう!
スポンサーリンク
内部関数とは?
Pythonでは、関数内に関数を定義することができます。
def outer_func():
# 外側の関数の処理
def inner_func():
# 内側の関数の処理
# 外側の関数の処理
このような関数のことを「内部関数」や「関数のネスト」と呼びます。
内側の関数(inner_func
)は、関数の外側から直接呼び出すことができないので外側の関数内で呼び出したり、関数の参照を戻り値として返したりします。
def outer_func():
def inner_func():
pass
# 外側の関数内で呼び出す
inner_func()
# 戻り値で内側の関数の参照を返す
return inner_func
クロージャ(関数閉包)
クロージャ(closure)とは、外側の関数内で宣言された変数や受け取った引数を記憶した内側の関数のこと を言います。
クロージャを内包した関数を「エンクロージャ(enclosure)」と呼びます。
# エンクロージャ
def outer_func(arg):
# 関数内で宣言した変数(ローカル変数)
num = 1
# クロージャ
def inner_func():
# outer_func関数の引数と変数を足した値を返す
return arg + num
# クロージャを返す
return inner_func
# inner_funcを代入
f = outer_func(10)
print(f()) # 11
本来ならばouter_func
関数の引数arg
とローカル変数num
は、関数を抜けた時点で消滅しますが、クロージャを生成したことによりinner_func
関数内に値が記憶されたので演算し、結果を返すことができました!
エンクロージャのローカル変数の値を書き換える
先ほどのコードでは、outer_func
関数のローカル変数num
をクロージャ内で書き換えるとエラーとなります。
def outer_func(arg):
num = 1
def inner_func():
# outer_func関数のローカル変数を書き換えてみる
num += 1
return arg + num
return inner_func
f = outer_func(10)
print(f())
実行結果
Traceback (most recent call last):
File "/Users/user/Desktop/Python/main.py", line 13, in <module>
print(f())
File "/Users/user/Desktop/Python/main.py", line 7, in inner_func
num += 1
UnboundLocalError: local variable 'num' referenced before assignment
グローバルを除く1つ外側のスコープで先に束縛された変数の値を書き換えるには、nonlocal
文を使って再束縛する必要があります。
def outer_func(arg):
num = 1
def inner_func():
# numを再束縛
nonlocal num
# 再束縛したので書き換え可能
num = 100
return arg + num
return inner_func
f = outer_func(10)
print(f()) # 110
このコードを応用することで呼び出すたびに更新されるような関数を定義することができます。
def outer_func():
count = 0
def inner_func():
# 再束縛
nonlocal count
# 1ずつ増やす
count += 1
return count
return inner_func
f = outer_func()
print(f()) # 1
print(f()) # 2
print(f()) # 3
f
に変数が記憶されているので呼び出すたびにcount
が更新されます。