Pythonのクロージャ、nonlocalの使い方
Author: 水卜
Author: 水卜
def counter():
cnt = [0]
print("counter")
def inner():
cnt[0] += 1
print(f"countup {cnt}")
return inner
counter = counter()
# counter
counter()
# countup [1]
counter()
# countup [2]
この例ではcounter()
にカウントアップするcnt変数を定義し、その中で定義されたinner()
でカウントアップしている。
このようにネストされた関数のことをクロージャと呼ぶ。
inner()
がクロージャ、counter()
がエンクロージャ。
Pythonでは外の関数のスコープの変数に代入することはできない。
代入はできないが、ミュータブルオブジェクトの書き換えはできるため、cnt
はここではList型としている。
クロージャは外側のスコープの変数を記憶しておくことができる。
エンクロージャを変数に格納すれば、cntはクロージャが記憶しているため、値を保持したままカウントアップできる。
counter = counter()
# counter
counter()
# countup [1]
counter()
# countup [2]
先ほどはクロージャからスコープ外で定義された変数に代入できず、スコープ外の変数をイミュータブルなList型にすることで書き換えを可能にした。
この場合nonlocalを使うとより簡潔に解決できる。
def counter():
cnt = 0
print("counter")
def inner():
nonlocal cnt
cnt += 1
print(f"countup {cnt}")
return inner
counter = counter()
# counter
counter()
# countup 1
counter()
# countup 2
nonlocalで宣言されたスコープ外の変数は、クロージャの中でも代入が可能である。
globalという宣言の仕方もある。
globalの場合、global変数をクロージャの中で扱うことができる。
cnt = 0
def counter():
print("counter")
def inner():
global cnt
cnt += 1
print(f"countup {cnt}")
return inner