让
a = [-1, -2, -3]
。我想修改列表 a
以便 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) 似乎进入无限循环,尽管其中一个通常只是另一个的语法糖版本?
如示例所示,
a += b
不等于a = a + b
,并且这个答案解释了原因。
在底层,
a += b
调用__iadd__
,当a
是一个列表时,它会迭代b
,将b
的每个元素添加到a
。然而,a = a + b
将在(第二个)__add__
上调用a
,它将尝试将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]
,然后 still 继续(因为现在 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__
执行一种类型检查以确保它连接的东西是一个列表。因此, +=
会导致无限循环,而 +
会导致错误。