【问题标题】:Python: &= operatorPython:&= 运算符
【发布时间】:2015-02-08 15:09:16
【问题描述】:

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

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

正如预期的那样,tmp 将为 {2,3},但我不知道为什么 s1 也将其值更改为 {2,3}。

但是,如果我这样做:

tmp = tmp & s2

那么,s1 将保持不变!谁能帮我解释一下&= 运算符下面会发生什么?

【问题讨论】:

  • 您应该按值而不是按引用复制s1

标签: python python-2.7 python-3.x set


【解决方案1】:

set 的&= (set.__iadd__) 与& (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;
}

【讨论】:

    【解决方案2】:

    它叫做intersection_update。 返回集合 s 只保留在 t 中找到的元素。正如你在这张照片中看到的那样;

    你正在重建第一个带有交叉点的集合。

    【讨论】:

      【解决方案3】:

      按值而不是按引用复制集合

      tmp = set(s1)
      

      (因为s1 是set 的一个实例)

      【讨论】:

        【解决方案4】:

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

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

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

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

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

        返回对象的“身份”。这是一个整数,它是 保证在此对象期间是唯一且恒定的 寿命。具有非重叠生命周期的两个对象可能具有相同的生命周期 id() 值。

        CPython 实现细节:这是对象在内存中的地址。

        Link to Python docs in id() function

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

        因此,当您更改其中一个时,另一个也会更改。实际上,我在最后一句中所说的在技术上并不正确,因为没有“两者”,只有一个集合对象在内存中具有两个不同的引用(tmp 和 s1)。

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

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

        真正的 Python 似乎在解释对象引用(带有名称/变量)方面做得很好,link to the page。

        【讨论】:

          猜你喜欢
          • 2012-06-03
          • 1970-01-01
          • 2012-07-11
          • 2013-06-13
          • 2020-08-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多