&=
演算子と|=
演算子を使用して2つのセットを試そうとすると、奇妙な結果が得られました。
s1 = {1,2,3}
s2 = {2,3,4}
tmp = s1
tmp &= s2
予想どおり、tmpは{2,3}になりますが、s1
も値を{2,3}に変更した理由がわかりません。
ただし、私が行う場合:
tmp = tmp & s2
その後、s1
は変更されません。誰かが&=
演算子の下で何が起こるか説明してくれませんか?
&=
(set.__iadd__
) for set
は &
(set.__add
) 。
set &= ...
は set.intersection_update
セットをインプレースで更新します。
関連するCPythonコード(Object/setobject.c
):
set_iand(PySetObject *so, PyObject *other)
{
PyObject *result;
if (!PyAnySet_Check(other))
Py_RETURN_NOTIMPLEMENTED;
result = set_intersection_update(so, other); // <----
if (result == NULL)
return NULL;
Py_DECREF(result);
Py_INCREF(so);
return (PyObject *)so;
}
それは呼ばれています intersection_update
。 tにもある要素のみを保持するセットsを返す。この写真でわかるように、
最初のセットを交差点で再構築しています。
セットを参照ではなく値でコピーする
tmp = set(s1)
(s1
はset
のインスタンスなので)
予期しない結果を引き起こしているのは_&=
_演算子ではなく、Pythonがメモリにオブジェクトを格納し、それらを変数(名前)で参照する方法です。
Pythonはすべてオブジェクトであり、メモリのどこかに格納されます。変数を宣言すると、Pythonに格納されている特定のオブジェクトを参照していることを伝えます変数名をそのオブジェクトへの参照として使用して、メモリ内の特定の場所。
組み込みのid()
関数を使用して、オブジェクトのメモリ位置に関する情報を取得できます。例:
_s1 = {1,2,3}
s2 = {2,3,4}
tmp = s1
id(tmp)
1763330653544
id(s1)
1763330653544
_
組み込みid()
関数に関する情報:
オブジェクトの「アイデンティティ」を返します。これは、このオブジェクトの存続期間中、一意で一定であることが保証されている整数です。重複しない存続期間を持つ2つのオブジェクトは、同じid()値を持つことができます。
CPython実装の詳細:これは、メモリ内のオブジェクトのアドレスです。
ご覧のとおり、id()
関数を使用すると、tmp
と_s1
_の名前で参照されるオブジェクトは同じになります。これは、返される整数値が同じであるためです。
したがって、どちらか一方を変更すると、もう一方も同様に変更されます。実際、最後の文で私が言っていることは技術的には正しくありません。「どちら」も存在せず、2つの異なる参照(tmp
と_s1
_)を持つ1つのセットオブジェクトだけがメモリに存在するためです。
_s1 = {3, 4, 5}
s2 = s1
s2.add(6)
s1
{3, 4, 5, 6}
id(s1)
1763330653320
id(s2)
1763330653320
_
ただし、これが常に単純であるとは限らないため、これを理解したい場合は、Pythonメモリ管理と変数参照を調べることをお勧めします。
Real Pythonは、オブジェクトの参照(名前/変数を使用)を説明する良い仕事をしているようです)、 ページへのリンク 。