復習を込めて授業をサラッと見ていたらnonlocalとglobalに。自問自答してパット答えられなかったのでqiitaに書くことに。
global and nonlocal
そもそもなんでこんなのが必要なのかというと、(pythonでは)プログラムは一度処理を終えてしまうとメモリが自動的に消えてしまうので次回同じプログラムを開始させても初期状態からスタートしてしまう。状況によってはそれが不都合だとされることがある。そこでnonlocal (or global)。これを使えば処理を終えても指定した変数の記録を残して次の処理を実行できるというわけだ。詳しくは一番下の例を。
_
globalsays that whenever it seesx0(that's when thex0is mentioned inside off2), we will go for the definition ofx0in the global frame.
nonlocalsays whenever you seex1mentioned, we will look forx1in some frame outside off2
x = 0
def outer():
x = 1
def inner():
x = 2
print("inner:", x)
inner()
print("outer:", x)
outer()
print("global:", x)
# inner: 2
# outer: 1
# global: 0
これにnonlocalを加えると
x = 0
def outer():
x = 1
def inner():
nonlocal x
x = 2
print("inner:", x)
inner()
print("outer:", x)
outer()
print("global:", x)
# inner: 2
# outer: 2
# global: 0
xの中身をそのままキープさせたい時などに役に立ちそう。
def stepper(num):
def step():
nonlocal num
num += 1
return num
return step
>>> stepper(4)()
5
たまたま自分で作ったメモを見つけたのでこれを元に。。
def counter():
count = 0
def counter():
count += 1
return count
return counter
# triggers unboundlocalerror since its not defined inside the counter func.
def counter2():
count = 0
def counter():
count = 0
count += 1
return count
return counter
"""
c = counter2() always returns 1
since each time the counter func gets called,
it creates another local frame with new info unless you have nonlocal within it
"""
def counter3():
count = 0
def counter():
nonlocal count
count += 1
return count
return count
対してglobalは
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でもnonlocalでもnested functionの中にある変数(1つのみ)を__globalとして扱うかnonlocal(ある意味local)として扱うか__だけの問題。globalを使えば指定した変数はglobal変数を無視してglobal xが定義されたところにあるxを参考にすると。
ちょっとした問題
>>> x0, y0 = 0, 0
>>> def g1(x1, y1):
... def f2():
... nonlocal x1
... global x0
... x0, x1 = 1,2
... y0, y1 = 1,2
... f2()
... print(x0, x1, y0, y1)
...
>>> g1(0,0)
1, 2, 0, 0
>>print(x0, y0)
1, 0
x0とx1がグローバルかノンローカルの違いを表している。
この例はもっとわかりやすいかもしれない。globalはnested funcitonの中に配置しないと意味が無い。
def f():
global x
def g(): x = 3 # Local x
g()
return x
>>> x = 0
>>> f()
0
def f():
def g():
global x
x = 3
g()
return x
>>>x = 0
>>> f()
3
直感的にわかりやすそうな例
def make_switcher(f,g,x,y):
"""
a function, which takes in two funcs, f and g, and two #s, x and y. It returns a new function that performs f x-times, and then switches to g for y-times, and then back to f, etc. Assume that f and g each take one arg.
>>>crazy_ivan = make_switcher(lambda x: x*x, lambda x: x+1, 2, 1)
>>>crazy_ivan(4)
16
>>>crazy_ivan(5)
25
>>>crazy_ivan(4)
5
>>>crazy_ivan(4)
16
"""
counter = 0
def swithcer(n):
nonlocal counter, f, g, x, y
if counter == x:
counter = 0
f,g = g,f
x, y = y, x
counter += 1
return f(n)
return swithcer
その他、参考になりそうなもの
pythontutor.comも役に立つが個人的には自分で書いていったほうが楽しいのでレクチャーにあったショートハンドを参考にしながら勉強するのも面白そうだ。分かりやすく、覚えやすい。
