列表插入超出范围的索引 - 表现得像追加

时间:2014-09-15 02:47:28

标签: python python-2.7

我有一个清单

 a = [1, 2, 3]

当我做的时候

a.insert(100, 100)

[1, 2, 3, 100]

因为列表最初的大小为4,我试图在索引100处插入值,它表现得像追加而不是抛出任何错误,因为我试图插入一个甚至不存在的索引。

不应该抛出

  

IndexError:列表分配索引超出范围

异常,因为它抛出时 我试图做

a[100] = 100

问题: 1.任何想法为什么它被设计为静默处理它而不是通知用户异常?

个人意见:

让我们看看其他语言在这种情况下的表现如何:

Ruby:

    > a = [1, 2]
    > a[100] = 100
    > a
 => [1, 2, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 100] 

ruby​​处理这个问题的方式非常清楚,至少对我来说听起来很有意义。

Java:

在java中,方法.add(index,value)如果应用索引超出范围(例如arraylist,linkedlist)将抛出 java.lang.IndexOutOfBoundsException。

所以我觉得要么它应该抛出异常(如java所做),要么在它们之间的范围内插入null(因为ruby处理它)。 但是在python中处理的无声方式只是令人沮丧。

更新(2014年9月16日IST上午8:30):

正如其中一位回答者所说,我在python-dev中发布了这个问题,我收到了回复。可以在此python dev mailing list thread中看到。如果你发现线程链接已经改变,你可以通过google search找到答案,在python dev的开头附加一个问题标题。

7 个答案:

答案 0 :(得分:15)

来自 docs

  

list.insert(i,x)
  在给定位置插入项目。第一个参数是要插入的元素的索引,所以   a.insert(0,x)插入列表的前面,a.insert(len(a),   x)相当于a.append(x)。

从技术上讲,当您执行a.insert(100, 100)时,它确保{/ 1}}将在 100之前的索引中插入,在这种情况下,恰好是索引3。

此外,我们可以查看the implementation

100

答案 1 :(得分:9)

文档说:

L.insert(index, object) # insert object before index

所以当你尝试在索引100处插入它时,它真的会在100之前获得列表中的现有索引。

答案 2 :(得分:5)

Perhaps the actual implementation will shed some light.

static int
ins1(PyListObject *self, Py_ssize_t where, PyObject *v)
{
    ...
    if (where > n)
        where = n;
    ...
}

这样就回答了如何解决问题。

哲学上,列表不是数组,并且有许多列表操作可以容忍奇怪的索引。例如,l [1:1000]将返回[2,3]。这对程序员来说都是一种方便。

答案 3 :(得分:3)

a.insert(len(a), x) supposed的行为与a.append(x)的行为相同。在查看方法的source code之后:

static int
ins1(PyListObject *self, Py_ssize_t where, PyObject *v)
{
    Py_ssize_t i, n = Py_SIZE(self);

    ...

    if (where > n)
        where = n;
    ...

}

通过将len(a)上方的任何int设置为n,您将看到它以相同的方式处理n上方的任何int。

因此:如果作为int >= len(a)的第一个参数传递,任何list.append(x)都会像list.insert(i, x)一样。

官方python文档可能只推荐len(a)作为一种方便的方法来确保您始终输入的数字大于列表的长度。

答案 4 :(得分:2)

Python的创建者Guido van Rossum在python-dev邮件列表上的评论(查看September 2014 archives;根据我的经验,特定邮件的确切网址可能会不时发生变化),以回应OP在该清单上交叉提出这个问题:

  

2014年9月15日星期一下午3:46,马克劳伦斯   写道:

     
    

我认为它基于切片的概念。从文档" s.insert(i,x) - 在由i给出的索引处将x插入s(与s [i:i] = [x]相同)"。

  
     

啊,对。它匹配像s [100:]的thigs,如果s是空字符串   短于100。

在另一个回复中:

  

这个功能自Python早期就已经存在,即使我们都认为它是错误的,我们也无法改变它 - 它只会破坏过多的现有代码。我不记得为什么我这样做了,但这绝对是一个有意识的选择;可能是一些对称或边缘情况。 (注意它在另一端也是这样工作的 - 如果一个元素少于100个,a.insert(-100,x)将在a的开头插入x。)

最终,这种事情是一个设计决定。几乎总是存在竞争问题,你永远找不到对每个人都很直观的东西。只需看看不同语言处理概念的方式有多少,如True和False(在某些语言中,它们与数字1和0相同;在某些语言中,任何非零都是True;在某些语言中,True和False与字符' 1'和' 0'(是的,真的!);在某些语言中,它们与数字或任何其他非严格布尔类型完全不兼容;在某些语言中,空容器是假的,在其他语言中它们是真的;选择一直在继续)。或者看看nil / null / None,它们也与布尔和其他计算有趣的交互。有些语言甚至有可能。

Python处理列表插入的方式在某些情况下很方便,而且有足够的人发现它们编写的代码可以使用并依赖于插入行为。也许文档可能是 little 更清晰,但它真的不是那么不清楚;无论如何,一旦你尝试它,你会看到它的作用,并相应地编写你的Python代码。

答案 5 :(得分:1)

当您将单个元素插入列表时,列表的长度将只增加一个 - 不多于,而不是更少。

答案 6 :(得分:0)

不是将插入与项目分配进行对比,而是更类似于切片分配,因为两者都会改变列表的大小。

>>> a = [1, 2, 3]
>>> a[100:100] = [100]
>>> a
[1, 2, 3, 100]

切片也不会引发IndexError,因此与:

一致
a.insert(100, 100)