i = i + n是否真的与i + = n相同? [英] Is i = i + n truly the same as i += n?
问题描述
一个代码块有效,而另一块无效.这是有意义的,除了第二个块与第一个块相同之外,只有使用简写形式的操作.它们实际上是相同的操作.
l = ['table']
i = []
版本1
for n in l:
i += n
print(i)
输出:['t', 'a', 'b', 'l', 'e']
版本2
for n in l:
i = i + n
print(i)
输出:
TypeError:只能将列表(而不是"str")串联到列表
是什么导致这个奇怪的错误?
它们不必相同.
使用+
运算符将调用方法__add__
,而使用+=
运算符将调用__iadd__
.完全取决于所讨论的对象,当调用这些方法之一时会发生什么.
如果您使用x += y
,但是x
不提供__iadd__
方法(或者该方法返回NotImplemented
),则将__add__
用作后备广告,这意味着x = x + y
发生.
对于列表,使用l += iterable
实际上使用iterable
的元素扩展了列表l
.在您的情况下,在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
.
奖励
内德·巴切尔德(Ned Batchelder)的挑战,以便在文档中找到它 >
One block of code works but the other does not. Which would make sense except the second block is the same as the first only with an operation written in shorthand. They are practically the same operation.
l = ['table']
i = []
Version 1
for n in l:
i += n
print(i)
Output: ['t', 'a', 'b', 'l', 'e']
Version 2
for n in l:
i = i + n
print(i)
Output:
TypeError: can only concatenate list (not "str") to list
What is causing this strange error?
They don't have to be the same.
Using the +
operator calls the method __add__
while using the +=
operator calls __iadd__
. It is completely up to the object in question what happens when one of these methods is called.
If you use x += y
but x
does not provide an __iadd__
method (or the method returns NotImplemented
), __add__
is used as a fallback, meaning that x = x + y
happens.
In the case of lists, using l += iterable
actually extends the list l
with the elements of iterable
. In your case, every character from the string (which is an iterable) is appended during the extend
operation.
Demo 1: using __iadd__
>>> l = []
>>> l += 'table'
>>> l
['t', 'a', 'b', 'l', 'e']
Demo 2: using extend
does the same
>>> l = []
>>> l.extend('table')
>>> l
['t', 'a', 'b', 'l', 'e']
Demo 3: adding a list and a string raises a TypeError
.
>>> l = []
>>> l = l + 'table'
[...]
TypeError: can only concatenate list (not "str") to list
Not using +=
gives you the TypeError
here because only __iadd__
implements the extending behavior.
Demo 4: common pitfall: +=
does not build a new list. We can confirm this by checking for equal object identities with the is
operator.
>>> 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]
However, the l = l + iterable
syntax does build a new list.
>>> 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
[]
In some cases, this can produce subtle bugs, because +=
mutates the original list, while
l = l + iterable
builds a new list and reassigns the name l
.
BONUS
Ned Batchelder's challenge to find this in the docs
这篇关于i = i + n是否真的与i + = n相同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!