web-dev-qa-db-ja.com

スコープ規則の簡単な説明

Pythonのスコープ規則は正確に何ですか?

私がいくつかのコードを持っているならば:

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

xはどこにありますか?いくつかの可能な選択肢は以下のリストを含みます:

  1. 囲んでいるソースファイル内
  2. クラス名前空間
  3. 関数定義内
  4. Forループインデックス変数内
  5. Forループの内側

関数spamが他の場所に渡されたときの実行中のコンテキストもあります。そして、おそらく ラムダ関数 は少し違った方法で渡しますか?

単純な参照またはアルゴリズムがどこかにあるはずです。中級のPythonプログラマーにとっては混乱する世界です。

438
Charles Merriam

実際のところ、Pythonスコープの解決のための簡潔な規則は、 Pythonの学習から、第3回です。編 (これらの規則は、属性ではなく変数名に固有のものです。ピリオドなしで参照した場合、これらの規則が適用されます。)

LEGBルール.

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

E、Enclosing-function locals - 内側から外側に向かって、すべての静的包含関数(defまたはlambda)のローカルスコープ内の名前です。

G、Global(module) - モジュールファイルの最上位レベルで割り当てられた名前、またはファイル内のglobal内のdefステートメントの実行によって割り当てられた名前。

B、組み込み(Python) - 組み込みの名前モジュールで事前に割り当てられた名前:openrangeSyntaxError、...

だから、の場合

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

Forループには独自のネームスペースはありません。 LEGBの順番では、スコープは次のようになります。

L:ローカル、def spam内(code3code 4code5内).

E:囲まれた関数、それを囲む関数(例全体が別のdefにある場合)

G:グローバル。モジュール内でグローバルに宣言されたxがありましたか(code1)。

B:Pythonに組み込まれているすべてのx

xcode2に含まれることは決してありません(期待される場合であっても、 Anttiの答え または を参照してください )。

386
Rizwan Kassim

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

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

  • スパムの範囲 - code3とcode5で定義されたすべてのもの(およびcode4、ループ変数)を含む

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

  • 組み込み名前空間。ちょっと特別なケース - これは様々なPython組み込み関数とlen()やstr()のような型を含みます。一般的にこれはいかなるユーザコードによっても変更されるべきではないので、それは標準的な関数と他には何も含まないことを期待します。

より多くのスコープは、ネストした関数(またはラムダ)を図に導入したときにのみ表示されます。これらはあなたが期待していたのとほとんど同じように振る舞うでしょう。ネストした関数は、ローカルスコープ内のすべてのもの、およびそれを囲む関数のスコープ内のすべてのものにアクセスできます。例えば。

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ではglobalと同じように機能する新しいキーワード "nonlocal"が導入されていますが、入れ子にされた関数スコープのために。

148
Brian

Python3の時間に関して完全な答えはありませんでしたので、ここで答えを作りました。

他の回答で提供されているように、Local、Enclosing、Global、Builtinの4つの基本的なスコープ、LEGBがあります。これらに加えて、特別なスコープ、クラス本体があります。これはクラス内で定義されたメソッドのスコープを構成しません。クラス本体内の代入は、それ以降の変数をクラス本体内にバインドします。

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

クラス本体の特殊性を実証する

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.

現在のスコープに対してローカルであるとは見なされていない変数、またはそれを包含するスコープは、グローバル変数です。グローバル名はモジュールのグローバル辞書で調べられます。見つからなかった場合、グローバルはビルトインモジュールから検索されます。モジュールの名前がpython 2からpython 3に変更されました。 python 2では__builtin__であり、python 3では現在builtinsと呼ばれています。ビルトインモジュールの属性に割り当てた場合、そのモジュールが同じ名前の独自のグローバル変数でそれらを隠していない限り、それはその後モジュールから読み取り可能なグローバル変数として見えるようになります。


組み込みモジュールを読むことも役に立つでしょう。ファイルの一部にpython 3スタイルの印刷機能が必要だとしますが、ファイルの他の部分ではprintステートメントを使用します。 Python 2.6-2.7では、Python 3 print関数を手に入れることができます:

import __builtin__

print3 = __builtin__.__dict__['print']

from __future__ import print_functionは実際にはPython 2のどこにもprint関数をインポートしません - 代わりにそれは他の変数識別子のようにprintを扱い、現在のモジュールのprint文の解析規則を無効にします。したがって、print関数を組み込み関数で検索することができます。

104
Antti Haapala

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

編集:これはこれに関する詳細な情報を含む PEP です。

21
Jeremy Cantrell

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

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
20
brianray

Pythonは、3つの名前空間を使って変数を解決します。

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

globalslocalsの2つの関数があり、これらの名前空間のうちの2つの内容を表示します。

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

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

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

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

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

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

クラス定義内では、名前はクラス名前空間の一部です。たとえばcode2はクラス名で修飾する必要があります。通常はFoo.code2です。しかし、self.code2はPythonオブジェクトがフォールバックとして包含クラスを見ているのでうまくいきます。

オブジェクト(クラスのインスタンス)はインスタンス変数を持ちます。これらの名前はオブジェクトの名前空間にあります。それらはオブジェクトによって修飾されなければなりません。 (variable.instance

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

PythonスコープルールPythonスコープ変数スコープ を参照してください。

11
S.Lott

Xはどこにありますか?

xは定義されていないので見つかりません。 :-)それを置くと、code1(global)またはcode3(local)にあります。

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

Pythonは静的スコープなので、 'spam'を別の関数に渡しても、スパムはそれが由来するモジュール(code1で定義されている)やその他のスコープ(下記参照)のグローバルにアクセスすることができます。 code2のメンバーは再びselfを通してアクセスされます。

ラムダは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 2.1以前、および2.1からは、from-future-importを使用して特別に機能を要求しない限り) - fun1とfun2のスコープはfun3には表示されないため、S.Lottの答えが成り立ち、グローバルx :

0 0
7
bobince

Pythonでは、

値が割り当てられた変数は、その割り当てが現れるブロックに対してローカルです。

現在のスコープ内に変数が見つからない場合は、LEGBの順番を参照してください。

0
GraceMeng