一个代码块有效,而另一块无效。除了第二个块与第一个块相同外,这是有意义的,只是第二个块用简写形式进行操作。它们实际上是相同的操作。
for n in l:
i += n
print(i)
['t', 'a', 'b', 'l', 'e']
输出:for n in l:
i = i + n
print(i)
{{1}}
输出:
TypeError:只能将列表(而不是“ str”)连接到列表
是什么导致这个奇怪的错误?
答案 0 :(得分:79)
它们不必相同。
使用+
运算符调用方法__add__
,而使用+=
运算符调用__iadd__
。完全取决于所讨论的对象,当调用这些方法之一时会发生什么。
如果您使用x += y
但x
不提供__iadd__
方法(或者该方法返回NotImplemented
),则将__add__
用作 fallback ,表示发生x = x + y
。
对于列表,使用l += iterable
实际上使用l
的元素扩展了列表iterable
。对于您而言,在extend
操作期间会附加字符串中的每个字符(可迭代)。
演示1:使用__iadd__
>>> l = []
>>> l += 'table'
>>> l
['t', 'a', 'b', 'l', 'e']
演示2:使用extend
可以做到
>>> l = []
>>> l.extend('table')
>>> l
['t', 'a', 'b', 'l', 'e']
演示3:添加列表和字符串会引发TypeError
。
>>> l = []
>>> l = l + 'table'
[...]
TypeError: can only concatenate list (not "str") to list
此处不使用+=
会为您提供TypeError
,因为只有__iadd__
实现了扩展行为。
演示4:常见陷阱:+=
不会建立新列表。我们可以通过使用is
运算符检查对象是否相等来确认这一点。
>>> l = []
>>> l_ref = l # another name for l, no data is copied here
>>> l += [1, 2, 3] # uses __iadd__, mutates l in-place
>>> l is l_ref # confirm that l and l_ref are names for the same object
True
>>> l
[1, 2, 3]
>>> l_ref # mutations are seen across all names
[1, 2, 3]
但是,l = l + iterable
语法确实会建立一个新列表。
>>> l = []
>>> l_ref = l # another name for l, no data is copied here
>>> l = l + [1, 2, 3] # uses __add__, builds new list and reassigns name l
>>> l is l_ref # confirm that l and l_ref are names for different objects
False
>>> l
[1, 2, 3]
>>> l_ref
[]
在某些情况下,这可能会产生细微的错误,因为+=
变异原始列表,而
l = l + iterable
建立一个新列表,并重新分配名称l
。
奖励
答案 1 :(得分:3)
如果在第二种情况下,您将列表包装在n
周围,以避免出现错误:
for n in l:
i = i + [n]
print(i)
你得到
['table']
所以它们是不同的操作。
答案 2 :(得分:3)
否。
7.2.1. Augmented assignment statements:
可以将
x += 1
之类的扩展赋值表达式重写为x = x + 1
,以达到相似但不完全相等的效果。在扩展版本中,x仅被评估一次。另外,如果可能, 实际操作是就地执行的,这意味着 创建一个新对象并将其分配给目标(旧对象) 而是修改。