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

Har*_*nam 21 python python-2.7

我有一份清单

 a = [1, 2, 3]
Run Code Online (Sandbox Code Playgroud)

我什么时候做的

a.insert(100, 100)

[1, 2, 3, 100]
Run Code Online (Sandbox Code Playgroud)

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

它应该不扔

IndexError:列表赋值索引超出范围

当我尝试做的时候会抛出异常

a[100] = 100
Run Code Online (Sandbox Code Playgroud)

问题: 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] 
Run Code Online (Sandbox Code Playgroud)

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邮件列表线程中看到.如果您发现线程链接已更改,您可以通过谷歌搜索在python dev开头附加的问题标题找到答案.

alf*_*sin 15

来自文档:

list.insert(i,x)
在给定位置插入一个项目.第一个参数是要插入的元素的索引,因此a.insert(0,x)插入列表的前面,而a.insert(len(a),x)等同于a.append( X).

所以从技术上讲,当你这样做时a.insert(100, 100),确保100 100 之前的索引中插入,在这种情况下,索引3.

此外,我们可以看一下实现:

static int
ins1(PyListObject *self, Py_ssize_t where, PyObject *v)
{
    Py_ssize_t i, n = Py_SIZE(self);
    PyObject **items;
    if (v == NULL) {
        PyErr_BadInternalCall();
        return -1;
    }
    if (n == PY_SSIZE_T_MAX) {
        PyErr_SetString(PyExc_OverflowError,
            "cannot add more objects to list");
        return -1;
    }

    if (list_resize(self, n+1) == -1)
        return -1;

    if (where < 0) {
        where += n;
        if (where < 0)
            where = 0;
    }
    if (where > n)  // <-- Here the implementation handles indexes > list-len
        where = n;
    items = self->ob_item;
    for (i = n; --i >= where; )
        items[i+1] = items[i];
    Py_INCREF(v);
    items[where] = v;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 棘手的措辞.之前!=之前. (4认同)
  • @ApproachingDarknessFish:但这非常荒谬。我们是否必须假设在某些实现中`[1, 2, 3].insert(2, "foo")`可能会产生`["foo", 1, 2, 3]`?因为“0”在“2”之前...我一点也不喜欢这个。我也预计会出现“IndexError”,尤其是在这种喜欢“raise”的语言中。:/ (4认同)

小智 9

文件说:

L.insert(index, object) # insert object before index
Run Code Online (Sandbox Code Playgroud)

因此,当您尝试在索引100处插入时,它将真正获得100之前的列表上的现有索引.


xav*_*ier 5

也许实际的实施将会有所启发.

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

所以这回答了如何做的问题.

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


Joh*_*n Y 5

Python 的创建者 Guido van Rossum 在python-dev邮件列表上的评论(查看2014 年 9 月的档案;根据我的经验,特定消息的确切 URL 会不时发生变化),以回应 OP 交叉发布此问题在该名单上:

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

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

啊,对了。它匹配像 s[100:] 这样的东西,如果 s 小于 100,则它是空字符串。

在另一个回应中:

这个功能从 Python 诞生之初就已经存在,即使我们都同意它是错误的,我们也无法更改它——它只会破坏太多现有代码。我不太记得为什么要这样做,但这绝对是一个有意识的选择;可能存在某种对称性或边缘情况。(请注意,它在另一端也以这种方式工作 - 如果 a 的元素少于 100 个,a.insert(-100, x) 将在 a 的开头插入 x。)

归根结底,这种事情是一个设计决定。几乎总是存在相互竞争的问题,而且你永远找不到每个人都直观的东西。只要看看不同的语言有多少种方式处理像 True 和 False 这样的基本概念(在某些语言中,它们与数字 1 和 0 相同;在某些语言中,任何非零都是 True;在某些语言中 True 和 False 与数字 1 和 0 相同)。字符“1”和“0”(是的,真的!);在某些语言中,它们与数字或任何其他非严格布尔类型完全不兼容;在某些语言中,空容器是 False,在其他语言中,它们是 True;选择无穷无尽)。或者看看 nil/null/None,它们也与布尔值和其他计算有有趣的交互。有些语言甚至有 Maybe。

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