2
>>> x = []
>>> y = [1,2,3]
>>> def func1(L):
...     x+=L
... 
>>> def func2(L):
...     x.extend(L)
... 
>>> func1(y)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in func1
UnboundLocalError: local variable 'x' referenced before assignment
>>> func2(y)
>>> x
[1, 2, 3]

リストextend()メソッドが非グローバル変数を変更できるのに、+ =演算子は変更できないのはなぜですか?私の理解では、関数が変数を割り当てない限り、グローバル指定なしで変数を読み取ることができます。ただし、この場合、関数は値を設定します。

4

1 に答える 1

5

値を設定するのではなく、既存の値を変更します。Pythonでは、名前を値にバインドすることと、値を変更(または変更)することは別のことです。

リストの場合、この操作はリストをインプレースで変更するように定義されているため、本当の問題はなぜ+= 機能しないのかということです。答えは、その演算子が割り当てのように見えるため、スコープとバインドの目的で割り当てのように動作させることが決定されたということです。 ドキュメントには次のように書かれています(強調が追加されました):

拡張代入は、ターゲット(通常の代入ステートメントとは異なり、アンパックすることはできません)と式リストを評価し、2つのオペランドの代入のタイプに固有の二項演算を実行し、結果を元のターゲットに割り当てます。

つまり、拡張割り当てには操作の一部としての割り当てが含まれるため、通常のスコープ/バインディングルールが適用されます。ターゲットはターゲットとして評価されるため、関数の場合はローカル変数として扱われます。したがって、xがリストの場合は、x += newList事実上次のようになります。

x.extend(newList)
x = x

より一般的には、拡張代入はオペランドをインプレースで変更できますが、それでも結果の値を元の変数に再バインドしようとします。したがってx += other、基本的に次のように機能します。

y = x.__iadd__(other)
x = y
于 2012-11-24T19:36:33.100 に答える