2010-12-26 7 views
4

Reason for unintuitive UnboundLocalError behaviourをフォローアップします(あなたが読んだと仮定します)。 次のPythonスクリプトを考えてみましょう:直感的なUnboundLocalErrorビヘイビアの理由2

def f(): 
    # a+=1   # 1 
    aa=a 
    aa+=1 

    # b+='b'  # 2 
    bb=b 
    bb+='b' 

    c[0]+='c'  # 3 
    c.append('c') 
    cc=c 
    cc.append('c') 

    d['d']=5  # Update 1 
    d['dd']=6  # Update 1 
    dd=d   # Update 1 
    dd['ddd']=7  # Update 1 

    e.add('e')  # Update 2 
    ee=e   # Update 2 
    ee.add('e')  # Update 2 

a=1 
b='b' 
c=['c'] 
d={'d':4}   # Update 1 
e=set(['e'])  # Update 2 
f() 
print a 
print b 
print c 
print d    # Update 1 
print e    # Update 2 

スクリプトの結果は次のとおりです。

1 
b 
['cc', 'c', 'c'] 
{'dd': 6, 'd': 5, 'ddd': 7} 
set(['e']) 

コメントアウト行(1,2印)がI UnboundLocalErrorとSO質問を通じて希望線であり、参照する理由を説明します。しかし、3のマークが付いた線が動作します!

デフォルトでは、リストはPythonで参照によってコピーされるため、ccが変更されたときにcが変更されることは理解できます。しかし、なぜPythonは、メソッドのスコープからaとbを直接変更することができなければ、最初にcを変更できるようにするべきですか?

デフォルトリストがPythonでリファレンスとしてコピーされているという事実は、この設計の決定に一貫性がないのはどうかわかりません。

私は何が欠けていますか?

UPDATES:完全性については

  • また、私はまた、セットを追加しましたつまり、私はソースコードを追加し、さらに完全を期すため# Update
  • で更新をマークし、上記の質問に辞書同等を追加しました同等。このセットの動作は、実際は私にとって驚くべきことです。リストや辞書に似たような行動を期待していました...
+1

"デフォルトではリストは参照としてコピーされています。"これは誤りです。すべてが参考になります。しかし、リストは可変オブジェクトであり、整数は不変です。 Pythonがどのように実際に動作するかを反映するために用語を更新すると役に立ちます。 –

+0

訂正のための@ S.Lott: – Jonathan

答えて

3

文字列および整数とは異なり、Pythonのリストは可変オブジェクトです。つまり、それらは変更されるように設計されています。ライン

c[0] += 'c' 

は名前cがバインドされているものに変更することはありません

c.__setitem__(0, c.__getitem__(0) + 'c') 

を言うと同じです。この電話の前後で、cは同じリスト–です。変更されたのはのです。

は、二行目はcローカル名になりますので、あなたは、同じUnboundLocalErrorが発生していた機能f()、中

c += ['c'] 
c = [42] 

を言っていたし、最初の行が必要

c = c + ['c'] 

に変換しますcという名前はすでに(このローカルスコープ内で)まだ何かにバインドされています。

+0

良い例と非常に明確な答え。私はまだそれが直感的ではないと思っています(特に、あなたが実証したように、リストにはさまざまな変更が影響を与えます)。 – Jonathan

+1

短いストーリー: 'expr [expr] = expr'は' name = expr'ではありません。 – delnan

+0

\ @delnan - なぜあなたのセットはリストとdictとは異なる動作をするのか知っていますか? (私は結果を示すために上記の質問を更新しました – Jonathan

2

重要なことは、これはどのオブジェクトですか?行a += 1は、どの整数が参照しているかを変更しています。整数は不変なので、1から2に変更するときは、実際にはa = a + 1と同じです。参照するのに全く新しい整数を与えています。

一方、c[0] += 'c'は、リストcが参照するものは変更されず、最初の要素が参照する文字列が変更されるだけです。リストは変更可能であるため、同一のリストは同一性を変更することなく変更できます。