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


340

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

Pythonの公式Webサイトにhelp("nonlocal")はドキュメントがなく、動作しません。



18
非ローカル向けの公式のPythonウェブサイトドキュメントは次のとおりです:docs.python.org/3/reference/…(このドキュメントはPython 3.0以降で利用可能であるため、公式ドキュメントがないというOPのアサーションは間違っていました)
wkschwartz

3
"There is no documentation for nonlocal".実際、help(keyword_in_string)Python 3以降のドキュメントで実行できます
ytpillai

10
公平を期すために、公式のドキュメントはこの件について少々うんざりしています。選択された回答の例は、物事を非常に明確にし、これを貴重な質問にします。
Mad Physicist

公式のPythonチュートリアルであり、スコープと名前空間の概念の良い説明との素敵な例が
jammon 2016年

回答:


471

使用せずにこれを比較してください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()のことはx今もあるouter()S ' 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

32
それはグローバルxとどう違うのですか?
ooboo 2009

52
非常に似ていますが、例では外側のxはグローバルではなく、外側の関数で定義されています。
Anon、

3
@Dustin-実際には、属性xを持つクラスAとサブクラスBが定義されている場合、B内からxをAxとして参照します
Anon

2
内部関数を定義すると、コードは簡単に大きくインデントされ、79文字のPEP8推奨に違反します。この問題を回避する方法はありますか?内部関数を外部関数の外側に配置することはできますか?質問が愚かに聞こえることは知っていますが、私は本気です。
tommy.carstensen 2015

3
@ tommy.carstensenでは、高次関数の美点である引数として関数を渡すことができます。関数型プログラミングでもこれはコンポジションと呼ばれ、Pythonは純粋なFP言語ではありませんが、機能(ジェネレーター、高次関数はいくつかの例です)で遊ぶことができ
ます

90

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


41

「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ですが、最初のバージョンは初心者にはもう少しわかりやすいようです。返された関数を呼び出してジェネレータを適切に使用することは、混乱の共通点です。最初のバージョンは明示的に関数を返します。


1
それがキーワード 'global'がすることだと確信していました-その名前の変数に到達するまで、より高い環境を処理します。変数xは、モジュールレベル、クラス内、次にこのクラス内の関数、次にその関数の内部関数で個別に宣言できます。どのxを参照するかをどのようにして知るのでしょうか。
ooboo 2009

7
グローバルについてのことは、それがグローバル変数に対してのみ機能するということです。囲んでいる非グローバルスコープの変数は参照できません。
SingleNegationElimination 2009年

make_counterを試しましたが、ジェネレータではなく関数が返されます。後でジェネレーターを反復できるようにジェネレーターを返す方法はありますか?
Dejell 2013

@Dejel:この例はnonlocal、Pythonでステートメントを説明することを目的としています。自然数のシーケンスが必要な場合、Pythonイディオムは実際にはitertools.count()
SingleNegationElimination

ここでは、yieldのようにジェネレーターを返す機能をデモしたいと思います。yieldは実際にはジェネレーターを返します。私の考えは、yieldを使用せず、代わりに非ローカルまたは別のソリューションを使用することです
Dejell

15

@ooboo:

ソースコードの参照ポイントに「最も近い」ものを1つ使用します。これは「字句スコープ」と呼ばれ、40年以上の間標準となっています。

Pythonのクラスメンバーは、実際には、 __dict__にあり、字句スコープによって到達されることはありません。

指定しない場合nonlocalしかしやるx = 7、それが「X」の新しいローカル変数を作成します。を指定nonlocalすると、「最も近い」「x」が検出され、それに割り当てられます。指定した場合nonlocalして「x」がない場合は、エラーメッセージが表示されます。

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


14

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


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

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

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

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

以下も参照してください。

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

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

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


11
毎日新しいことを学びましょう。help()キーワードで使用できるとは思いもしませんでした(そして今、私の心は吹き飛ばされhelp()ています:引数なしでインタラクティブになります)。
Erik Youngren

6

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

3
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)

2

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


0

「非ローカル」内部関数(つまり、ネストされた内部関数)を使用すると、外部親関数の特定の変数に対する読み取りおよび「書き込み」権限取得できます。そして非ローカルは内部関数内でのみ使用できます。例:

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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.