为什么Python列表添加必须是同质的?

Mar*_*cin 24 python language-design language-implementation python-internals

任何熟悉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']
Run Code Online (Sandbox Code Playgroud)

为什么x+"foo"以上不会返回与x上述成绩单中的最终值相同的值?

这个问题来自NPE的问题:Python列表+ = iterable的行为是否记录在何处?

更新:我知道不需要异质+=工作(但确实如此),同样,并不要求异质+是错误.这个问题是为什么做出后一种选择.

很难说将序列添加到列表中的结果是不确定的.如果这是一个充分的反对意见,那么防止异质性是有意义的+=.Update2:特别是,python总是将操作符调用委托给左侧操作数,因此没有问题出现"什么是正确的事情"":左手对象总是管理(除非它委托到右边).

更新3:对于任何人认为这是一个设计决定,请解释(a)为什么没有记录; 或(b)如有文件记录.

Update4:"应该[1] + (2, )返回什么?" 它应该返回一个结果值,该值等于x最初[1]紧跟在之后的变量的值x+=(2, ).这个结果定义明确.

Gar*_*tty 11

来自Python的禅宗:

面对模棱两可,拒绝猜测的诱惑.

让我们来看看这里发生了什么:

x + y
Run Code Online (Sandbox Code Playgroud)

这给了我们一个价值,但是它是什么类型的?当我们在现实生活中添加东西时,我们希望类型与输入类型相同,但如果它们是完全不同的呢?那么,在现实世界中,我们拒绝添加1"a",它没有任何意义.

如果我们有类似的类型怎么办?在现实世界中,我们看一下背景.计算机不能这样做,所以它必须猜测.Python选择左操作数并让它决定.由于缺乏上下文,您的问题就出现了.

说程序员想做["a"] + "bc"- 这可能意味着他们想要"abc"["a", "b", "c"].目前,解决方案是调用"".join()第一个操作数或list()第二个操作数,这允许程序员做他们想要的事情,并且清晰明确.

你的建议是让Python猜测(通过内置规则来选择给定的操作数),所以程序员可以通过添加来做同样的事情 - 为什么这样更好?它只是意味着错误地获取错误类型更容易,我们必须记住任意规则(左操作数选择类型).相反,我们得到一个错误,因此我们可以为Python提供正确调用所需的信息.

那为什么+=不同呢?好吧,那是因为我们正在为Python提供上下文.通过就地操作,我们告诉Python修改一个值,所以我们知道我们正在处理我们正在修改的值的类型.这是Python需要进行正确调用的上下文,因此我们不需要猜测.

当我谈论猜测时,我在谈论Python猜测程序员的意图.这是Python做了很多事情 - 请参阅3.x中的分部./浮点除法,纠正它在2.x中的整数除法的误差.

这是因为当我们试图划分时,我们隐含地要求浮动划分.Python将此考虑在内,并根据它完成操作.同样,这是关于猜测意图.当我们添加+我们的意图时尚不清楚.当我们使用时+=,它非常清楚.

  • "面对模棱两可,拒绝猜测的诱惑." 这个答案没有解释(a)为什么涉及任何猜测; 或(b)为什么在异类的"+ ="中没有猜测.后者的结果是明确定义的,因为python总是将操作符调用委托给左操作数."因为我们正在为Python提供上下文." 由于如何评估运算符调用,Python*总是*具有该上下文. (3认同)
  • 但是,我会争辩说,"+ ="做"猜".至少,"a = a + b"和"a + = b"之间的区别令人困惑.注意,对于"a = 1"和"b = 0.5","a + = b"给出"a == 1.5". (3认同)
  • @Lattyware对我来说,最有意义的是`x + = y`应该与`x = x + y`具有相同的结果.如果他们不同,我会很惊讶(我在这种情况下).在这种情况下,我希望它们都不起作用. (2认同)
  • @Marcin这是一个争论为什么`x + = y`其中`x`是一个列表而```不是不行的,我想说也许这是对的,但这不是一个让`x的论据在上下文工作中= x + y`,这肯定会使事情变得不那么明显. (2认同)

Mar*_*cin 9

这些错误报告表明这种设计怪癖是一个错误.

问题12318:

是的,这是预期的行为,是的,它是不一致的.

这已经很久了,Guido说他不会再这样做了(这是他的遗憾名单).但是,我们不会通过更改代码来破坏代码(list.__iadd__就像工作一样list.extend).

Issue575536:

目的是list.__iadd__完全符合 list.extend().也没有必要进行超广泛化 list.__add__():这是一个特征,那些不想被类似马丁的例子感到惊讶的人可以通过使用普通+列表来避免它们.

(当然,有些人发现这种行为非常令人惊讶,包括打开该bug报告的开发人员).

(感谢@Mouad找到这些).