Python 式 i += x と i = i + x は同等ですか?答えが「はい」の場合、おめでとうございます。半分しか正解していないのはなぜですか。 私たちの一般的な理解によれば、整数演算に関しては両者に類似点も相違点もありませんが、リスト演算についても同様でしょうか。まず、次の 2 つのコードを見てください:
コード 1
>>> l1 = range(3) >>> l2 = l1 >>> l2 += [3] >>> l1 [0, 1, 2, 3] >>> l2 [0, 1, 2, 3]
コード 2
>>> l1 = range(3) >>> l2 = l1 >>> l2 = l2 + [3] >>> l1 [0, 1, 2] >>> l2 [0, 1, 2, 3]
コード 1 とコード 2 の l2 の値は同じですが、l1 の値は異なり、i += x であることを示しています。そして、i = i + x は等価ではありません。では、どのような状況では等価であり、どのような状況では等価ではないのでしょうか?
この問題を明確にする前に、まず変更可能なオブジェクトと不変オブジェクトという 2 つの概念を理解する必要があります。
Python のオブジェクトには、一意の識別子、型、値という 3 つの共通属性があります。
一意の識別: メモリ内のオブジェクトの一意性を識別するために使用されます。関数 id() はオブジェクトの一意の識別を表示できます。
タイプ: オブジェクトがサポートする操作を決定します。たとえば、リストには長さ属性を含めることができますが、整数にはサポートしません。同様に、オブジェクトの型が決定されると、関数 type() はオブジェクトの型情報を返すことができます。
オブジェクトの値は一意の識別子とは異なります。一部のオブジェクトの値は、特定の操作によって変更できるわけではありません。その値を変更可能なオブジェクトと呼びます。値を変更できないオブジェクトは、不変オブジェクト (immutable) と呼ばれます
不変オブジェクト (immutable)
不変オブジェクトの場合、値は常に最初に作成されたときの値であり、オブジェクトに対する操作はすべて新しいオブジェクトになります。オブジェクトの作成。
>>> a = 1 >>> id(a) 32574568 >>> a += 1 >>> id(a) 32574544
整数「1」は不変オブジェクトです。最初に割り当てられたとき、a は整数オブジェクト 1 を指しますが、変数 a に対して += 演算を実行すると、a は別の整数オブジェクト 2 を指しますが、オブジェクト 1 は不変オブジェクトです。まだ何も変更されておらず、変数 a はすでに新しいオブジェクト 2 を指しています。一般的な不変オブジェクトには、int、tuple、set、str が含まれます。
可変オブジェクト (可変)
可変オブジェクトの値は、リスト オブジェクトなどの特定の操作を通じて動的に変更できます。append メソッドを通じてリストに要素を継続的に追加できます。変数オブジェクトが 2 つの変数に割り当てられると、それらは同じインスタンス オブジェクトを共有し、どちらかの変数を操作すると、もう一方の変数にも影響します。
>>> x = range(3) >>> y = x >>> id(x) 139726103041232 >>> id(y) 139726103041232 >>> x.append(3) >>> x [0, 1, 2, 3] >>> y [0, 1, 2, 3] >>> id(x) 139726103041232 >>> id(y) 139726103041232
+= オペレーションはまずオブジェクトの __iadd__ メソッドの呼び出しを試みます。そのようなメソッドがない場合は、次に __add__ メソッドの呼び出しを試みます
__add__。と __iadd__ の差分
__add__ メソッドは 2 つのパラメーターを受け取り、それらの合計を返します。両方のパラメーターの値は変わりません。
__iadd__ メソッドも 2 つのパラメーターを受け取りますが、これはインプレース操作であり、最初のパラメーターの値を変更することを意味します。これはオブジェクトが変更可能である必要があるため、不変オブジェクト用の __iadd__ メソッドはありません。
>>> hasattr(int, '__iadd__') False >>> hasattr(list, '__iadd__') True
明らかに、整数オブジェクトには __iadd__ がありませんが、リスト オブジェクトには __iadd__ メソッドが用意されています。
>>> l2 += [3] # 代码1:使用__iadd__,l2的值原地修改
コード 1 の += 操作は __iadd__ メソッドを呼び出し、l2 が指すオブジェクトの値をその場で変更します
>>> l2 = l2 + [3] # 代码2:调用 __add__,创建了一个新的列表,赋值给了l2
コード 2 の + 操作は __add__ メソッドを呼び出し、このメソッドは新しいオブジェクトを返します。元のオブジェクトは変更されず、l1 は依然として元のオブジェクトを指し、l2 はすでに新しいオブジェクトを指しています。
上記は式 i += x と i = i + x の違いです。したがって、関数のパラメータで変数オブジェクトをキーワード パラメータとして使用すべきでないのと同様に、l2 の変更により l1 も変更されるため、リストに対して += 演算を実行するときに潜在的なバグが存在します。