web-dev-qa-db-ja.com

Python:&=演算子

&=演算子と|=演算子を使用して2つのセットを試そうとすると、奇妙な結果が得られました。

s1 = {1,2,3}
s2 = {2,3,4}
tmp = s1
tmp &= s2 

予想どおり、tmpは{2,3}になりますが、s1も値を{2,3}に変更した理由がわかりません。

ただし、私が行う場合:

tmp = tmp & s2

その後、s1は変更されません。誰かが&=演算子の下で何が起こるか説明してくれませんか?

20
OhMyGosh

&=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;
}
12
falsetru

それは呼ばれています intersection_updatetにもある要素のみを保持するセットsを返す。この写真でわかるように、

enter image description here

最初のセットを交差点で再構築しています。

6
GLHF

セットを参照ではなく値でコピーする

tmp = set(s1)

s1setのインスタンスなので)

3

予期しない結果を引き起こしているのは_&=_演算子ではなく、Pythonがメモリにオブジェクトを格納し、それらを変数(名前)で参照する方法です。

Pythonはすべてオブジェクトであり、メモリのどこかに格納されます。変数を宣言すると、Pythonに格納されている特定のオブジェクトを参照していることを伝えます変数名をそのオブジェクトへの参照として使用して、メモリ内の特定の場所。

組み込みのid()関数を使用して、オブジェクトのメモリ位置に関する情報を取得できます。例:

_s1 = {1,2,3}
s2 = {2,3,4}
tmp = s1
id(tmp)
1763330653544
id(s1)
1763330653544
_

組み込みid()関数に関する情報:

オブジェクトの「アイデンティティ」を返します。これは、このオブジェクトの存続期間中、一意で一定であることが保証されている整数です。重複しない存続期間を持つ2つのオブジェクトは、同じid()値を持つことができます。

CPython実装の詳細:これは、メモリ内のオブジェクトのアドレスです。

Python id()関数のドキュメント)へのリンク

ご覧のとおり、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は、オブジェクトの参照(名前/変数を使用)を説明する良い仕事をしているようです)、 ページへのリンク

0
Rik Schoonbeek