仅仅使用 += "语法糖" 如何导致无限循环?
设定一个列表 a = [-1, -2, -3]
。我想把这个列表修改成 a == [-1, -2, -3, 1, 2, 3]
,并且想用 map
来实现这个目标。
我写了以下几段代码来尝试实现这个功能:
a = a + map(abs, a)
a = a + list(map(abs, a))
a += map(abs, a)
a += list(map(abs, a))
结果如下:
TypeError: can only concatenate list (not "map") to list
- 正常工作:
a = [-1, -2, -3, 1, 2, 3]
- 无限挂起,最后被终止,没有错误信息(可能是内存不够了?)
- 正常工作:
a = [-1, -2, -3, 1, 2, 3]
我原以为 a += b
只是 a = a + b
的一种简写方式,但根据(1)和(3)的表现,显然并不是这样。
为什么(1)会报错,而(3)似乎进入了无限循环,尽管一般来说它们应该是同一种写法的不同表现?
1 个回答
从例子可以看出,a += b
和 a = 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__
会进行类型检查,以确保它要连接的东西是一个列表。因此,+=
会导致无限循环,而 +
则会出现错误。