2012-03-23 6 views
1

囲み関数で定義されたリストを変異させることによって、期待どおり下記(不合理なく例示)コードが動作する:オブジェクトの変更がPythonのスコープ上でどのような影響を与えますか?

def outside1(): 
    l = list('abcd') 
    def inside(a): 
     print "Before - %i: %r" % (id(l), l) 
     l.append(a) 
     print "After - %i: %r\n" % (id(l), l) 
    return inside 

f = outside1() 
[f(c) for c in 'efgh'] 

このコードはまた囲む範囲で定義された不変で囲まれた範囲内でアクセス可能であることを示す動作します。

def outside2(): 
    t = tuple('abcd') 
    def inside(): 
     print "%i: %r" % (id(t), t) 
    return inside 

outside2()() 

しかしこれはlocal variable 't' referenced before assignmentで失敗します。

def outside3(): 
    t = tuple('abcd') 
    def inside(a): 
     print "Before - %i: %r" % (id(t), t) 
     t = t + (a,) 
     print "After - %i: %r\n" % (id(t), t) 
    return inside 

f = outside3() 
[f(c) for c in 'efgh'] 

ことができる人の電子ここで何が起こっているの?私の最初の推測では、私は突然変異することができますが、囲みスコープに割り当てることはできませんでしたが、の前にのprint文がoutside2の働きをする前に動作すると予想していました。

答えて

6

Pythonはコンパイル時に名前のスコープを静的に検出します。関数内で割り当てられる名前は、その関数にとってローカルになります。だから、ライン

t = t + (a,) 

inside()へのローカルtをレンダリングし、inside()内部tのいずれかのルックアップは、inside()のローカル変数を検索しようとします。上記の行を実行すると、tはまだ存在しないため、エラーです。 Pythonの3.xでは

nonlocalとして、明示的tを宣言することでその問題を解決することができます。このすべては無常とは全く無関係である

def outside3(): 
    t = tuple('abcd') 
    def inside(a): 
     nonlocal t 
     print("Before - %i: %r" % (id(t), t)) 
     t = t + (a,) 
     print("After - %i: %r\n" % (id(t), t)) 
    return inside 

。リストを使用したあなたの例は、lという名前を再割り当てしませんが、タプルを使用する例ではは再割り当てtです。これは重要な違いであり、変更可能性ではありません。

+0

"コンパイル中にPythonが名前のスコープを静的に検出しました。"ありがとう、それは簡単な答えです。 py3kのチップは素晴らしいボーナスです。 – Finn

3

変更はスコープに影響しません。

問題は、現在のスコープにない変数に代入するとその変数が作成され、その変数を読み取るだけではその変数が作成されないということです。

+0

Downvoter:あなたはここで何に同意しますか? – Marcin

+1

+1これは正解です – newacct

1

Marcinが正しい。ミュータビリティはスコープにはまったく影響しません。あなたは「リストを変異」している間、あなたが理解する必要がどのような

は、最初の例では、ある、あなたは、単に変数lを読み取り、それにいくつかの方法(.append())を呼び出しているlで指されます。これは、変数tを読んでいる2番目の例とまったく同じです。

どちらの場合でも、外部スコープ内の変数に代入するのではなく、単に変数を読み込むだけです。 Mutabilityは変数が指すものを変更できることを意味し、そのように変更を共有します。しかし、変数と範囲の点からは、全く違いはありません。

3番目の例では、変数tに割り当てています。それが違いです。 Python 2.xでは、グローバル変数以外の外部変数にはglobalで代入する方法がありません。 Python 3.xにはnonlocalがあります。可変性は、それとは何の関係もないことに注意してください:

:あなたはあなたの最初の例では、変数 l(単にオブジェクトがによって指さ変異するのではなく)にを割り当てる しようとした場合は、同じ問題に遭遇するだろう
def outside1(): 
    l = list('abcd') 
    def inside(a): 
     print "Before - %i: %r" % (id(l), l) 
     l = [1,2,3] 
     print "After - %i: %r\n" % (id(l), l) 
    return inside 
関連する問題