以下の nonlocal_1.py
を実行すると何が起きるでしょうか。
環境は Python 3.6.0とします (多少古いPython3でも変わりません)
def func():
nonlocal a
a = 10
a = 2
func()
print(a)
- 2 と表示される
- 10 と表示される
- ランタイムエラー (
RuntimeError
) を送出する - それ以外
答えは見えにくいように下の方にあります。
解説
そもそも nonlocal
の使う場所が変です。
nonlocalの仕様 によると
nonlocal 文は、列挙された識別子がグローバルを除く一つ外側のスコープで先に束縛された変数を参照するようにします。これは、束縛のデフォルトの動作がまずローカル名前空間を探索するので重要です。この文は、中にあるコードが、グローバル (モジュール) スコープ以外のローカルスコープの外側の変数を再束縛できるようにします。
nonlocal 文で列挙された名前は、 global 文で列挙された名前と違い、外側のスコープですでに存在する束縛を参照しなければなりません (新しい束縛が作られるべきスコープの選択が曖昧さを排除できません)。
よって上記のコードは文法エラーにて死にます。a = 2
を関数の前に置いたって無駄です。
ちなみに以下は動作します。
def func():
def func1():
nonlocal a
a = 10
a = 2
func1()
print(a)
func()
また、普通ならこんな場所に nonlocal
なんて書きませんということで
def func():
global a
a = 10
a = 2
func()
print(a)
これは動作します。 global
は指定された変数をglobal変数として解釈するのであって、存在する変数の有無は気にしません。
もう少し「使った」感じのする nonlocal
の例
import random
def func():
called = 0 # func1()が呼ばれた回数を記録したい
def func1(a):
nonlocal called
called += 1
return a + random.randrange(10)
tmp = 0
t = random.randrange(10)
for i in range(t):
tmp = func1(tmp)
print('func1()は{}回呼ばれた。結果は{}'.format(called, tmp))
func()
$ python nonlocal_3.py
func1()は8回呼ばれた。結果は39
$ python nonlocal_3.py
func1()は9回呼ばれた。結果は48
$ python nonlocal_3.py
func1()は1回呼ばれた。結果は8
$ python nonlocal_3.py
func1()は4回呼ばれた。結果は24
(答え)
$ python nonlocal_1.py
File "nonlocal_1.py", line 2
nonlocal a
SyntaxError: no binding for nonlocal 'a' found
感想
ちょっと人為的過ぎる例題でした。