503

Python スコープ ルールとは正確には何ですか?

コードがある場合:

code1
class Foo:
   code2
   def spam.....
      code3
      for code4..:
       code5
       x()

どこにありxますか?考えられる選択肢には、以下のリストが含まれます。

  1. 同封のソースファイル内
  2. クラスの名前空間で
  3. 関数定義で
  4. for ループ インデックス変数内
  5. for ループの内部

spamまた、関数が別の場所に渡される実行中のコンテキストもあります。また、ラムダ関数の渡し方が少し違うのではないでしょうか?

どこかに簡単な参照またはアルゴリズムがなければなりません。中級の Python プログラマーにとっては、紛らわしい世界です。

4

9 に答える 9

438

実は、Python スコープ解決の簡潔なルールは、Learning Python, 3rd. エド。. (これらの規則は、属性ではなく変数名に固有のものです。ピリオドなしで参照すると、これらの規則が適用されます。)

LEGB ルール

  • ローカル— 関数 (defまたはlambda) 内で何らかの方法で割り当てられ、その関数でグローバルに宣言されていない名前

  • エンクロージング関数 —内側から外側へ、すべての静的エンクロージング関数 (defまたは) のローカル スコープで割り当てられた名前lambda

  • グローバル(モジュール) — モジュール ファイルのトップレベルで、またはファイル内のglobalステートメントを実行することによって割り当てられる名前def

  • 組み込み(Python) — 組み込みの名前モジュールで事前に割り当てられた名前: openrangeSyntaxErrorなど

だから、の場合には

code1
class Foo:
    code2
    def spam():
        code3
        for code4:
            code5
            x()

forループには独自の名前空間がありません。LEGB の順序で、スコープは次のようになります。

  • L: ローカルdef spam( code3code4、およびcode5)
  • E: 囲み関数 (例全体が別の にある場合def)
  • G:xモジュール ( 内code1) でグローバルに宣言されたものはありましたか?
  • xB: Python の任意のビルトイン。

xで見つかることはcode2ありません(予想される場合でも、Anttiの回答またはこちらを参照してください)。

于 2008-11-15T12:47:22.537 に答える
158

基本的に、Python で新しいスコープを導入する唯一のものは関数定義です。クラスは、本体で直接定義されたものはすべてクラスの名前空間に配置されるという点で少し特殊なケースですが、含まれるメソッド (またはネストされたクラス) 内から直接アクセスすることはできません。

あなたの例では、 x が検索されるスコープは3つしかありません。

  • スパムのスコープ - コード 3 とコード 5 (およびコード 4、ループ変数) で定義されたすべてを含む

  • グローバル スコープ - code1 で定義されたすべてのものと Foo (およびその後に変更されたもの) を含む

  • ビルトインの名前空間。少し特殊なケース - これには、len() や str() などのさまざまな Python 組み込み関数と型が含まれています。通常、これはユーザー コードによって変更されるべきではないため、標準関数のみが含まれていることを期待してください。

ネストされた関数 (またはラムダ) を画像に導入する場合にのみ、より多くのスコープが表示されます。ただし、これらは期待どおりに動作します。ネストされた関数は、ローカル スコープ内のすべてのものにアクセスできます。また、外側の関数のスコープ内のすべてのものにアクセスできます。例えば。

def foo():
    x=4
    def bar():
        print x  # Accesses x from foo's scope
    bar()  # Prints 4
    x=5
    bar()  # Prints 5

制限:

ローカル関数の変数以外のスコープ内の変数にはアクセスできますが、追加の構文なしで新しいパラメーターに再バインドすることはできません。代入は、親スコープの変数に影響を与える代わりに、新しいローカル変数を作成します。例えば:

global_var1 = []
global_var2 = 1

def func():
    # This is OK: It's just accessing, not rebinding
    global_var1.append(4) 

    # This won't affect global_var2. Instead it creates a new variable
    global_var2 = 2 

    local1 = 4
    def embedded_func():
        # Again, this doen't affect func's local1 variable.  It creates a 
        # new local variable also called local1 instead.
        local1 = 5
        print local1

    embedded_func() # Prints 5
    print local1    # Prints 4

関数スコープ内からグローバル変数のバインディングを実際に変更するには、global キーワードで変数がグローバルであることを指定する必要があります。例えば:

global_var = 4
def change_global():
    global global_var
    global_var = global_var + 1

現在、関数スコープを囲む変数に対して同じことを行う方法はありませんが、Python 3 では新しいキーワード " nonlocal" が導入されています。これはグローバルと同様に機能しますが、ネストされた関数スコープに対して機能します。

于 2008-11-15T21:51:09.800 に答える
114

Python3の時間については、完全な回答がなかったので、こちらで回答しました。ここで説明する内容のほとんどは、Python 3 ドキュメントの4.2.2 名前の解決で詳しく説明されています。

他の回答で提供されているように、ローカル、エンクロージング、グローバル、ビルトインの 4 つの基本スコープ、LEGB があります。これらに加えて、クラス内で定義されたメソッドを囲むスコープを含まないクラス bodyという特別なスコープがあります。クラス本体内の割り当ては、そこからの変数をクラス本体にバインドします。

特に、and以外ブロック文は変数スコープを作成しません。Python 2 では、リスト内包表記は変数スコープを作成しませんが、Python 3 では、リスト内包表記内のループ変数が新しいスコープで作成されます。defclass

クラス本体の特性を示すため

x = 0
class X(object):
    y = x
    x = x + 1 # x is now a variable
    z = x

    def method(self):
        print(self.x) # -> 1
        print(x)      # -> 0, the global x
        print(y)      # -> NameError: global name 'y' is not defined

inst = X()
print(inst.x, inst.y, inst.z, x) # -> (1, 0, 1, 0)

したがって、関数本体とは異なり、クラス本体で変数を同じ名前に再割り当てして、同じ名前のクラス変数を取得できます。この名前をさらに検索すると、代わりにクラス変数に解決されます。


Python を初めて使用する多くの人にとって大きな驚きの 1 つは、forループが変数のスコープを作成しないことです。Python 2 では、リスト内包表記もスコープを作成しません (ジェネレーターと辞書内包表記は作成します!) 代わりに、関数またはグローバル スコープで値をリークします。

>>> [ i for i in range(5) ]
>>> i
4

内包表記は、Python 2 のラムダ式内で変更可能な変数を作成するための狡猾な (場合によってはひどい) 方法として使用できます。ラムダ式はdefステートメントのように変数スコープを作成しますが、ラムダ内ではステートメントは許可されません。割り当てが Python のステートメントであることは、ラムダでの変数の割り当てが許可されていないことを意味しますが、リスト内包表記は式です...

この動作は Python 3 で修正されました。内包式やジェネレーターが変数をリークすることはありません。


グローバルは実際にはモジュール スコープを意味します。メインの python モジュールは__main__; インポートされたすべてのモジュールは、sys.modules変数を介してアクセスできます。アクセスするには、または;__main__を使用できます。そこにアクセスして属性を割り当てることはまったく問題ありません。これらは、メイン モジュールのグローバル スコープ内の変数として表示されます。sys.modules['__main__']import __main__


名前が現在のスコープ (クラス スコープを除く) に割り当てられている場合、その名前はそのスコープに属していると見なされます。まだ、またはまったくない)、または最後にグローバルスコープ。変数がローカルと見なされているが、まだ設定されていないか削除されている場合、変数値を読み取るUnboundLocalErrorと、 のサブクラスである が生成されNameErrorます。

x = 5
def foobar():
    print(x)  # causes UnboundLocalError!
    x += 1    # because assignment here makes x a local variable within the function

# call the function
foobar()

スコープは、global キーワードを使用して、グローバル (モジュール スコープ) 変数を明示的に変更することを宣言できます。

x = 5
def foobar():
    global x
    print(x)
    x += 1

foobar() # -> 5
print(x) # -> 6

これは、スコープを囲んでいる場合でも可能です。

x = 5
y = 13
def make_closure():
    x = 42
    y = 911
    def func():
        global x # sees the global value
        print(x, y)
        x += 1

    return func

func = make_closure()
func()      # -> 5 911
print(x, y) # -> 6 13

Python 2 では、囲んでいるスコープの値を変更する簡単な方法はありません。通常、これは、長さが 1 のリストなど、変更可能な値を持つことによってシミュレートされます。

def make_closure():
    value = [0]
    def get_next_value():
        value[0] += 1
        return value[0]

    return get_next_value

get_next = make_closure()
print(get_next()) # -> 1
print(get_next()) # -> 2

ただし、python 3では、nonlocalが救助に来ます:

def make_closure():
    value = 0
    def get_next_value():
        nonlocal value
        value += 1
        return value
    return get_next_value

get_next = make_closure() # identical behavior to the previous example.

nonlocalドキュメントによると、

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

つまりnonlocal、常に名前がバインドされている最も内側の外側の非グローバル スコープを参照します (つまり、割り当てられ、forターゲット変数として、with句内で、または関数パラメーターとして使用されることを含みます)。


現在のスコープまたは外側のスコープに対してローカルであると見なされない変数は、グローバル変数です。グローバル名は、モジュールのグローバル ディクショナリで検索されます。見つからない場合、グローバルは builtins モジュールから検索されます。モジュールの名前が python 2 から python 3 に変更されました。Python 2 ではそうでしたが__builtin__、Python 3 では と呼ばれるようになりましbuiltinsた。builtins モジュールの属性に割り当てると、そのモジュールが同じ名前の独自のグローバル変数でそれらをシャドウしない限り、読み取り可能なグローバル変数として、その後任意のモジュールに表示されます。


組み込みモジュールを読むことも役に立ちます。ファイルの一部で python 3 スタイルの print 関数が必要であるが、ファイルの他の部分ではまだprintステートメントを使用しているとします。printPython 2.6-2.7 では、次の方法で Python 3関数を取得できます。

import __builtin__

print3 = __builtin__.__dict__['print']

は、from __future__ import print_function実際には Python 2 のどこにも関数をインポートしません。代わりに、現在のモジュール内のステートメントprintの解析規則を無効にし、他の変数識別子と同様に処理して、関数を組み込みで検索できるようにします。printprintprint

于 2014-05-05T11:08:54.970 に答える
25

スコープのもう少し完全な例:

from __future__ import print_function  # for python 2 support

x = 100
print("1. Global x:", x)
class Test(object):
    y = x
    print("2. Enclosed y:", y)
    x = x + 1
    print("3. Enclosed x:", x)

    def method(self):
        print("4. Enclosed self.x", self.x)
        print("5. Global x", x)
        try:
            print(y)
        except NameError as e:
            print("6.", e)

    def method_local_ref(self):
        try:
            print(x)
        except UnboundLocalError as e:
            print("7.", e)
        x = 200 # causing 7 because has same name
        print("8. Local x", x)

inst = Test()
inst.method()
inst.method_local_ref()

出力:

1. Global x: 100
2. Enclosed y: 100
3. Enclosed x: 101
4. Enclosed self.x 101
5. Global x 100
6. global name 'y' is not defined
7. local variable 'x' referenced before assignment
8. Local x 200
于 2015-12-04T17:38:37.673 に答える
23

Python 2.x のスコープ規則は、他の回答で既に概説されています。私が追加する唯一のことは、Python 3.0 には非ローカル スコープの概念もあるということです ('nonlocal' キーワードで示されます)。これにより、外部スコープに直接アクセスできるようになり、レキシカル クロージャーを含むいくつかの巧妙なトリックを実行できるようになります (変更可能なオブジェクトを含む醜いハックは必要ありません)。

編集:これに関する詳細情報を含むPEPを次に示します。

于 2008-11-15T18:52:49.257 に答える
15

Python は、一般に、利用可能な 3 つの名前空間を使用して変数を解決します。

実行中はいつでも、名前空間に直接アクセスできる少なくとも 3 つのネストされたスコープがあります。最初に検索される最も内側のスコープには、ローカル名が含まれます。最も近い外側のスコープから検索される、外側の関数の名前空間。次に検索される中央のスコープには、現在のモジュールのグローバル名が含まれます。最も外側のスコープ (最後に検索される) は、組み込みの名前を含む名前空間です。

これらの名前空間の 2 つの内容を表示するglobalsとの2 つの関数があります。locals

名前空間は、パッケージ、モジュール、クラス、オブジェクトの構築、および関数によって作成されます。他の種類の名前空間はありません。

この場合、名前付き関数の呼び出しxは、ローカル名前空間またはグローバル名前空間で解決する必要があります。

この場合の local は、メソッド function の本体ですFoo.spam

グローバルは -- まあ -- グローバルです。

ルールは、メソッド関数 (およびネストされた関数定義) によって作成されたネストされたローカル空間を検索してから、グローバルを検索することです。それでおしまい。

他のスコープはありません。forステートメント (および や などの他の複合ステートメントif)はtry、新しいネストされたスコープを作成しません。定義のみ (パッケージ、モジュール、関数、クラス、およびオブジェクト インスタンス)。

クラス定義内では、名前はクラスの名前空間の一部です。 code2たとえば、クラス名で修飾する必要があります。一般的にFoo.code2。ただし、self.code2Python オブジェクトは含まれているクラスをフォールバックとして参照するため、これも機能します。

オブジェクト (クラスのインスタンス) にはインスタンス変数があります。これらの名前は、オブジェクトの名前空間にあります。これらは、オブジェクトによって修飾されている必要があります。( variable.instance.)

クラスメソッド内から、ローカルとグローバルがあります。self.variableインスタンスを名前空間として選択すると言います。selfはすべてのクラス メンバー関数の引数であり、ローカル名前空間の一部になっていることに注意してください。

Python Scope RulesPython ScopeVariable Scopeを参照してください。

于 2008-11-15T02:03:38.967 に答える
9

x はどこにありますか?

x は、定義していないため見つかりません。:-)そこに置くと、code1(グローバル)またはcode3(ローカル)にある可能性があります。

code2 (クラス メンバー) は、同じクラスのメソッド内のコードからは見えません。通常は、self を使用してアクセスします。code4/code5 (ループ) は code3 と同じスコープに存在するため、そこに x を記述した場合、新しい x を作成するのではなく、code3 で定義された x インスタンスを変更することになります。

Python は静的にスコープが設定されているため、'spam' を別の関数に渡すと、spam は元のモジュール (code1 で定義) 内のグローバルと、それを含む他のスコープ (以下を参照) に引き続きアクセスできます。code2 メンバーは、再び self を介してアクセスされます。

lambda は def と同じです。関数内で使用されるラムダがある場合、ネストされた関数を定義するのと同じです。Python 2.2 以降では、ネストされたスコープが利用可能です。この場合、関数のネストの任意のレベルで x をバインドでき、Python は最も内側のインスタンスを取得します。

x= 0
def fun1():
    x= 1
    def fun2():
        x= 2
        def fun3():
            return x
        return fun3()
    return fun2()
print fun1(), x

2 0

fun3 は、fun2 に関連付けられた関数スコープである、最も近い包含スコープからインスタンス x を認識します。ただし、fun1 でグローバルに定義されている他の x インスタンスは影響を受けません。

nested_scopes の前 — Python pre-2.1、および from-future-import を使用して機能を具体的に要求しない限り 2.1 — fun1 と fun2 のスコープは fun3 には表示されないため、S.Lott の答えが保持され、グローバル x を取得します。 :

0 0
于 2008-11-15T12:44:59.920 に答える