任何熟悉Python内部(CPython或其他实现)的人都可以解释为什么列表添加需要是同质的:
In [1]: x = [1]
In [2]: x+"foo"
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
C:\Users\Marcin\<ipython-input-2-94cd84126ddc> in <module>()
----> 1 x+"foo"
TypeError: can only concatenate list (not "str") to list
In [3]: x+="foo"
In [4]: x
Out[4]: [1, 'f', 'o', 'o']
上面的x+"foo"
为什么不能在上面的记录中返回与x
的最终值相同的值?
这个问题来自NPE的问题:Is the behaviour of Python's list += iterable documented anywhere?
更新:我知道不需要异构+=
工作(但确实如此),同样,不要求异构+
成为错误。这个问题是为什么做出后一种选择。
很难说将序列添加到列表中的结果是不确定的。如果这是一个充分的反对意见,那么防止异质+=
是有意义的。 Update2:特别是,python总是将操作符调用委托给左边的操作数,所以没有问题出现“什么是正确的事情”:左手对象总是管理(除非它委托给右边)。
更新3:对于任何人认为这是一项设计决定,请解释(a)为何没有记录;或(b)记录在案的地方。
Update4:“应该[1] + (2, )
返回什么?”它应该返回一个结果值,该值等于x
之后最初持有[1]
的变量x+=(2, )
的值。这个结果定义明确。
答案 0 :(得分:11)
来自Python的禅宗:
面对模棱两可,拒绝猜测的诱惑。
让我们来看看这里发生了什么:
x + y
这给了我们一个价值,但是它是什么类型的?当我们在现实生活中添加东西时,我们希望类型与输入类型相同,但如果它们是完全不同的呢?好吧,在现实世界中,我们拒绝添加1
和"a"
,这没有意义。
如果我们有类似的类型怎么办?在现实世界中,我们看一下背景。计算机不能这样做,所以它必须猜测。 Python选择左操作数并让它决定。由于缺乏上下文,您的问题就出现了。
假设程序员想要["a"] + "bc"
- 这可能意味着他们想要"abc"
或["a", "b", "c"]
。目前,解决方案是在第一个操作数上调用"".join()
或在第二个操作数上调用list()
,这允许程序员执行他们想要的操作并且清晰明确。
您的建议是让Python猜测(通过内置规则来选择给定的操作数),因此程序员可以通过添加来做同样的事情 - 为什么更好?它只是意味着错误地获取错误类型更容易,我们必须记住任意规则(左操作数选择类型)。相反,我们会收到错误,因此我们可以为Python提供正确调用所需的信息。
为什么+=
会有所不同?好吧,那是因为我们正在为Python提供上下文。通过就地操作,我们告诉Python修改一个值,所以我们知道我们正在处理我们正在修改的值的类型。这是Python需要进行正确调用的上下文,因此我们不需要猜测。
当我谈论猜测时,我在谈论Python猜测程序员的意图。这是Python做了很多事情 - 请参阅3.x中的分部。 /
确实浮动除法,纠正它在2.x中的整数除法的错误。
这是因为当我们试图划分时,我们隐含地要求浮动除法。 Python将此考虑在内,并根据它完成操作。同样,这是关于猜测意图。当我们添加+
时,我们的意图尚不清楚。当我们使用+=
时,它非常清楚。
答案 1 :(得分:9)
这些错误报告表明这种设计怪癖是错误的。
是的,这是预期的行为,是的,它是不一致的。
很长一段时间以来,Guido说他不会再这样做了(这是在他的遗憾名单中)。但是,我们不会通过更改代码来破坏代码(
list.__iadd__
就像list.extend
一样工作。)
意图是
list.__iadd__
完全对应list.extend()
。没有必要进行超广泛化list.__add__()
也是:这是一个不这样做的人的特征 想要马丁般的例子可以避免让人惊讶 它们通过使用普通+
列表。
(当然,我们这些人发现这种行为非常令人惊讶,包括打开该错误报告的开发人员。)
(感谢@Mouad找到这些)。
答案 2 :(得分:1)
我相信Python设计师以这种方式添加,以便'+'运算符在结果类型方面保持一致的可交换性:type(a + b) == type(b + a)
每个人都希望1 + 2与2 + 1的结果相同。你期望[1] +'foo'与'foo'+ [1]相同吗?如果是,结果应该是什么?
您有3个选择,您可以选择左操作数作为结果类型,选择右操作数作为结果类型,或者引发错误。
+ =不可交换,因为它包含赋值。在这种情况下,您可以选择左操作数作为结果类型或抛出。令人惊讶的是,a += b
与a = a + b
不同。 a += b
不会将英语翻译为“添加到b并将结果分配给”。它转换为“将a添加到b”。这就是为什么它不能用于诸如字符串或元组之类的不可变量。
感谢您的评论。编辑了这篇文章。
答案 3 :(得分:0)
我的猜测是Python是强类型的,并且没有明确指示正确在这里做的事情。您是要求Python自己附加字符串,还是将字符串转换为列表(这是您表示希望它执行的操作)?
记住显式优于隐式。在最常见的情况下,这些猜测都不正确,你不小心试图做一些你没有意图的事情。提出一个TypeError并让你对其进行排序是最安全,最恐怖的事情。