web-dev-qa-db-ja.com

Python非ローカルステートメント

Python nonlocalステートメントは何をしますか(Python 3.0以降)。

公式のPythonウェブサイトにはドキュメントがなく、help("nonlocal")も機能しません。

284
ooboo

nonlocalを使用せずにこれを比較してください:

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を使用します。ここで、inner()xouter()xでもあります。

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

globalを使用する場合、xを適切な「グローバル」値にバインドします。

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
403
Anon

要するに、外部(ただし、非グローバル)スコープ内の変数に値を割り当てることができます。すべての厄介な詳細については、 PEP 3104 を参照してください。

79
Arkady

「python nonlocal」のグーグル検索では、提案 PEP 3104 が見つかりました。これは、ステートメントの背後にある構文と理由を完全に説明しています。つまり、関数に対してグローバルでもローカルでもない変数を参照するために使用されることを除いて、globalステートメントとまったく同じように機能します。

これでできることの簡単な例を以下に示します。カウンタージェネレーターは、これを使用するように書き換えて、クロージャーを持つ言語のイディオムのように見せることができます。

def make_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

明らかに、次のようにジェネレータとしてこれを書くことができます。

def counter_generator():
    count = 0
    while True:
        count += 1
        yield count

しかし、これは完全に慣用的なpythonですが、最初のバージョンは初心者にとってもう少し明白になるようです。返された関数を呼び出すことにより、ジェネレーターを適切に使用することは、混乱の共通点です。最初のバージョンは明示的に関数を返します。

help( 'nonlocal')nonlocalステートメント


    nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*

nonlocalステートメントにより、リストされた識別子は、最も近い囲みスコープ内の以前にバインドされた変数を参照します。バインディングのデフォルトの動作は、最初にローカル名前空間を検索することであるため、これは重要です。このステートメントにより、カプセル化されたコードは、グローバル(モジュール)スコープ以外のローカルスコープ外の変数を再バインドできます。

nonlocalステートメントにリストされている名前とは異なり、globalステートメントにリストされている名前は、囲みスコープ内の既存のバインディングを参照する必要があります(新しいバインディングを作成するスコープは明確に決定できません)。

nonlocalステートメントにリストされている名前は、ローカルスコープ内の既存のバインディングと競合してはなりません。

こちらもご覧ください:

PEP 3104-外部スコープの名前へのアクセス
nonlocalステートメントの仕様。

関連するヘルプトピック:グローバル、NAMESPACES

ソース: Python言語リファレンス

14
Yossi Truzman

@ooboo:

ソースコード内の参照ポイントに「最も近い」ものを取ります。これは「語彙スコーピング」と呼ばれ、40年以上の標準となっています。

Pythonのクラスメンバーは、実際には__dict__と呼ばれる辞書にあり、レキシカルスコープによって到達することはありません。

nonlocalを指定せずにx = 7を指定すると、新しいローカル変数「x」が作成されます。 nonlocalを指定すると、「最も近い」「x」を見つけて割り当てます。 nonlocalを指定し、「x」がない場合、エラーメッセージが表示されます。

キーワードglobalは、一番外側のものを除いて他のすべての "x"を喜んで無視するので、いつも奇妙に思えました。奇妙な。

14
a = 0    #1. global variable with respect to every function in program

def f():
    a = 0          #2. nonlocal with respect to function g
    def g():
        nonlocal a
        a=a+1
        print("The value of 'a' using nonlocal is ", a)
    def h():
        global a               #3. using global variable
        a=a+5
        print("The value of a using global is ", a)
    def i():
        a = 0              #4. variable separated from all others
        print("The value of 'a' inside a function is ", a)

    g()
    h()
    i()
print("The value of 'a' global before any function", a)
f()
print("The value of 'a' global after using function f ", a)
3
gxyd

「非ローカル」ステートメントの個人的な理解(およびPythonおよびプログラミング全般に不慣れなため、失礼します)は、「非ローカル」は反復関数内ではなくグローバル機能を使用する方法であるということです。コード本体。必要に応じて、関数間のグローバルステートメント。

2
Yossi Truzman

Python 3リファレンス からの引用:

非ローカルステートメントにより、リストされた識別子は、グローバルを除く最も近い囲みスコープで以前にバインドされた変数を参照します。

リファレンスで述べたように、いくつかのネストされた関数の場合、最も近い囲んでいる関数の変数のみが変更されます:

def outer():
    def inner():
        def innermost():
            nonlocal x
            x = 3

        x = 2
        innermost()
        if x == 3: print('Inner x has been modified')

    x = 1
    inner()
    if x == 3: print('Outer x has been modified')

x = 0
outer()
if x == 3: print('Global x has been modified')

# Inner x has been modified

「最近接」変数は、数レベル離れている場合があります。

def outer():
    def inner():
        def innermost():
            nonlocal x
            x = 3

        innermost()

    x = 1
    inner()
    if x == 3: print('Outer x has been modified')

x = 0
outer()
if x == 3: print('Global x has been modified')

# Outer x has been modified

ただし、グローバル変数にすることはできません。

def outer():
    def inner():
        def innermost():
            nonlocal x
            x = 3

        innermost()

    inner()

x = 0
outer()
if x == 3: print('Global x has been modified')

# SyntaxError: no binding for nonlocal 'x' found
2
Jeyekomon

「非ローカル」内部関数(つまり、ネストされた内部関数)を使用すると、読み取りと「write」権限外側の親関数の特定の変数の場合。また、非ローカルは内部関数内でのみ使用できます。例:

a = 10
def Outer(msg):
    a = 20
    b = 30
    def Inner():
        c = 50
        d = 60
        print("MU LCL =",locals())
        nonlocal a
        a = 100
        ans = a+c
        print("Hello from Inner",ans)       
        print("value of a Inner : ",a)
    Inner()
    print("value of a Outer : ",a)

res = Outer("Hello World")
print(res)
print("value of a Global : ",a)
0
NIPHIN