Python: &= 运算符

Python: &= operator

当我尝试使用 &=|= 运算符 or/and 两个集合时,我得到了一些奇怪的结果。

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

果然tmp是{2,3},不知道为什么s1也改成了{2,3}。

但是,如果我这样做:

tmp = tmp & s2

那么,s1不变!谁能为我解释 &= 运算符下面发生了什么?

叫做intersection_updatereturn 设置 s 只保留在 t 中也找到的元素。正如您在这张照片中看到的那样;

您正在重建第一个有交集的集合。

按值而不是按引用复制集

tmp = set(s1)

(因为 s1set 的一个实例)

&= (set.__iadd__) for set is implemented differently with & (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;
}

导致意外结果的不是 &= 运算符,而是 Python 在内存中存储对象并使用变量(名称)引用它们的方式。

Python中的一切都是一个对象,它存储在内存中的某个地方。声明一个变量只是告诉 Python 你正在引用存储在内存中特定位置的特定对象,使用变量名作为对该对象的引用。

您可以使用内置 id() 函数获取有关对象内存位置的一些信息,例如:

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

关于内置 id() 函数的一些信息:

Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.

CPython implementation detail: This is the address of the object in memory.

Link to Python docs in id() function

如您所见,通过使用id()函数,名称tmps1所引用的对象是相同的,因为返回的整数值是相同的.

所以,当你改变其中一个时,另一个也会改变。实际上,我在最后一句话中所说的在技术上是不正确的,因为没有 'either',内存中只有一组对象具有两个不同的引用(tmps1)。

s1 = {3, 4, 5}
s2 = s1
s2.add(6)
s1
{3, 4, 5, 6}
id(s1)
1763330653320
id(s2)
1763330653320

尽管并不总是这么简单,所以如果您想了解这一点,我建议您查找 Python 内存管理和变量引用。

真正的 Python 似乎很好地解释了对象引用(使用 names/variables),link to the page.