Help us understand the problem. What is going on with this article?

nonlocal一題

More than 3 years have passed since last update.

以下の nonlocal_1.py を実行すると何が起きるでしょうか。
環境は Python 3.6.0とします (多少古いPython3でも変わりません)

nonlocal_1.py
def func():
    nonlocal a
    a = 10

a = 2
func()
print(a)
  1. 2 と表示される
  2. 10 と表示される
  3. ランタイムエラー (RuntimeError) を送出する
  4. それ以外

答えは見えにくいように下の方にあります。

解説

そもそも nonlocal の使う場所が変です。

nonlocalの仕様 によると

nonlocal 文は、列挙された識別子がグローバルを除く一つ外側のスコープで先に束縛された変数を参照するようにします。これは、束縛のデフォルトの動作がまずローカル名前空間を探索するので重要です。この文は、中にあるコードが、グローバル (モジュール) スコープ以外のローカルスコープの外側の変数を再束縛できるようにします。

nonlocal 文で列挙された名前は、 global 文で列挙された名前と違い、外側のスコープですでに存在する束縛を参照しなければなりません (新しい束縛が作られるべきスコープの選択が曖昧さを排除できません)。

よって上記のコードは文法エラーにて死にます。a = 2 を関数の前に置いたって無駄です。

ちなみに以下は動作します。

nonlocal_2.py
def func():
    def func1():
        nonlocal a
        a = 10

    a = 2
    func1()
    print(a)

func()

また、普通ならこんな場所に nonlocal なんて書きませんということで

global_1.py
def func():
    global a
    a = 10

a = 2
func()
print(a)

これは動作します。 global は指定された変数をglobal変数として解釈するのであって、存在する変数の有無は気にしません。

もう少し「使った」感じのする nonlocal の例

nonlocal_3.py
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

感想

ちょっと人為的過ぎる例題でした。

amedama
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした