仅仅使用 += "语法糖" 如何导致无限循环?

1 投票
1 回答
47 浏览
提问于 2025-04-13 19:07

设定一个列表 a = [-1, -2, -3]。我想把这个列表修改成 a == [-1, -2, -3, 1, 2, 3],并且想用 map 来实现这个目标。

我写了以下几段代码来尝试实现这个功能:

  1. a = a + map(abs, a)
  2. a = a + list(map(abs, a))
  3. a += map(abs, a)
  4. a += list(map(abs, a))

结果如下:

  1. TypeError: can only concatenate list (not "map") to list
  2. 正常工作:a = [-1, -2, -3, 1, 2, 3]
  3. 无限挂起,最后被终止,没有错误信息(可能是内存不够了?)
  4. 正常工作:a = [-1, -2, -3, 1, 2, 3]

我原以为 a += b 只是 a = a + b 的一种简写方式,但根据(1)和(3)的表现,显然并不是这样。

为什么(1)会报错,而(3)似乎进入了无限循环,尽管一般来说它们应该是同一种写法的不同表现?

1 个回答

1

从例子可以看出,a += ba = a + b不一样的,而且这个回答解释了原因.

简单来说,a += b 会调用 __iadd__,当 a 是一个列表时,它会逐个遍历 b 中的元素,把每个元素加到 a 里去。但是,a = a + b 会在第二个 a 上调用 __add__,这会试图把 b 一下子加到第二个 a 上,但这个方法会发现 b 不是一个 list,所以会失败。

a += b 的情况下,会导致无限循环,因为 map 在遍历时,每次只计算并返回一个元素。因此,它会先返回第一个数字 abs(-1) == 1,这个数字会被加到 a 中,所以此时 a == [-1, -2, -3, 1]。然后,在添加之后,它会被要求返回第二个数字 abs(-2) == 2,这时 a == [-1, -2, -3, 1, 2]。这个过程会一直继续,直到 a == [-1, -2, -3, 1, 2, 3],然后还会继续(因为 a 中的值已经比最开始的三个值多了)。所以 map 接下来会返回 abs(1) == 1,这时 a == [-1, -2, -3, 1, 2, 3, 1],然后在下一步,a == [-1, -2, -3, 1, 2, 3, 1, 2],如此继续,直到内存用完。

总之,+= 调用 __iadd__,而 + 调用 __add__,它们的实现方式不同。 __iadd__ 函数可以在任何可迭代的对象上运行,但 __add__ 会进行类型检查,以确保它要连接的东西是一个列表。因此,+= 会导致无限循环,而 + 则会出现错误。

撰写回答