i = i + n与i + = n真的相同吗?

Luk*_*are 55 python operator-overloading python-3.x

一个代码块有效,但另一个代码没有.哪个是有意义的,除了第二个块与第一个块相同,只是用速记写的操作.它们实际上是相同的操作.

l = ['table']
i = []
Run Code Online (Sandbox Code Playgroud)

版本1

for n in l:
    i += n
print(i)
Run Code Online (Sandbox Code Playgroud)

输出: ['t', 'a', 'b', 'l', 'e']

版本2

for n in l:
    i = i + n
print(i)
Run Code Online (Sandbox Code Playgroud)

输出:

TypeError:只能将列表(不是"str")连接到列表


是什么导致了这个奇怪的错误?

tim*_*geb 79

它们不必相同.

使用+操作员__add__在使用+=操作员调用时调用该方法__iadd__.完全取决于所讨论的对象,当调用其中一个方法时会发生什么.

如果您使用x += y但未x提供__iadd__方法(或方法返回NotImplemented),则将__add__其用作后备,意味着x = x + y会发生这种情况.

在列表的情况下,使用l += iterable实际扩展列表l的元素iterable.在您的情况下,extend操作期间会附加字符串中的每个字符(可迭代).

演示1:使用 __iadd__

>>> l = []
>>> l += 'table'
>>> l
['t', 'a', 'b', 'l', 'e']
Run Code Online (Sandbox Code Playgroud)

演示2:使用extend也是如此

>>> l = []
>>> l.extend('table')
>>> l
['t', 'a', 'b', 'l', 'e']
Run Code Online (Sandbox Code Playgroud)

演示3:添加列表和字符串引发a TypeError.

>>> l = []
>>> l = l + 'table'
[...]
TypeError: can only concatenate list (not "str") to list
Run Code Online (Sandbox Code Playgroud)

不使用+=会给你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]
Run Code Online (Sandbox Code Playgroud)

但是,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
[]
Run Code Online (Sandbox Code Playgroud)

在某些情况下,这可能会产生细微的错误,因为它会+= 改变原始列表,同时
l = l + iterable构建一个列表并重新分配名称l.

奖金

Ned Batchelder在文档中找到这个的挑战