Подтвердить что ты не робот

Вставьте список в индекс, который находится далеко за пределами диапазона - ведет себя как добавление

У меня был список

 a = [1, 2, 3]

когда я сделал

a.insert(100, 100)

[1, 2, 3, 100]

поскольку список изначально имел размер 4, и я пытался вставить значение в индекс 100, он вел себя как append вместо того, чтобы бросать какие-либо ошибки, поскольку я пытался вставить индекс, который даже не существовал.

Если он не бросает

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] 

Как рубины справляются, это довольно ясно и звучит, по крайней мере, для меня.

Java:

В java метод .add(индекс, значение), если применяется с индексом, который выходит за пределы диапазона (например, в arraylist, связанный список) java.lang.IndexOutOfBoundsException.

Таким образом, я чувствовал, что либо он должен генерировать исключение (как java), либо вставлять нуль в диапазон между ними (поскольку рубин обрабатывает его). Но бесшумный способ обработки в python просто раскачивается.

ОБНОВЛЕНИЕ (16 сентября 2014 г. IST 8:30):

Как предложил один из респондентов, я разместил этот вопрос в python-dev, и я получил ответ. Это можно увидеть в этом списке рассылки python dev. Если вы обнаружите, что ссылка на нить изменилась, вы можете найти ответ, выполнив google search для названия вопроса, добавленного в начале с помощью python DEV.

4b9b3361

Ответ 1

Из docs:

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;
}

Ответ 2

В документации написано:

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

Итак, когда вы пытаетесь вставить в индекс 100, он действительно получит существующий индекс в списке до 100.

Ответ 3

Возможно, фактическая реализация прольет некоторый свет.

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

Итак, это отвечает на вопрос о том, как.

Философски, списки не являются массивами, и есть много манипуляций с списками, которые терпимы к странной индексации. Например, l [1:1000] вернет [2,3]. Все это предназначено для удобства программиста.

Ответ 4

a.insert(len(a), x) предположительно, чтобы действовать как a.append(x) для попустительства. Посмотрев исходный код метода:

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

    ...

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

}

Вы увидите, что он обрабатывает любой int выше len(a) таким же образом, установив любой int выше n на n.

Следовательно: любой int >= len(a) будет действовать так же, как list.append(x), если он передан как первый аргумент list.insert(i, x).

Официальные документы python, вероятно, рекомендуют только len(a) как удобный способ убедиться, что вы всегда вводите число, большее, чем длина списка.

Ответ 5

Когда вы вставляете один элемент в список, длина списка будет возрастать ровно одним - не более, не менее.

Ответ 6

Комментарии Guido van Rossum, создателя Python, в списке рассылки python-dev (отметьте архив за сентябрь 2014 года, по моему опыту, точные URL-адреса для определенных сообщений могут время от времени меняться), в ответ на перекрестный вызов этого вопроса в этом списке:

В понедельник, 15 сентября, 2014 в 15:46, Марк Лоуренс писал:

Я предполагаю, что это основано на концепциях нарезки. Из документов "s.insert(i, x) - вставляет x в s по индексу, указанному я (так же, как s [i: i] = [x])".

А, правильно. Он соответствует тигам, подобным s [100:], который является пустой строкой, если s менее 100.

И в другом ответе:

Эта функциональность существовала с самых ранних дней Python, и даже если бы мы все согласились, что это было неправильно, мы не могли ее изменить - это просто сломало бы слишком много существующего кода. Я не могу вспомнить, почему я сделал это таким образом, но это был определенно сознательный выбор; вероятно, какой-то симметрии или кромки. (Заметим, что он тоже работает на другом конце - a.insert(-100, x) будет вставлять x в начале a, если a имеет менее 100 элементов.)

В конечном счете, такая вещь - дизайнерское решение. Почти всегда есть конкурирующие проблемы, и вы никогда не сможете найти что-то, что будет интуитивно понятным для всех. Посмотрите, как много разных языков обрабатывают концепцию как фундаментальную, как True и False (на некоторых языках они идентичны числам 1 и 0, а на некоторых языках - ненулевое значение True, а на некоторых языках True и False идентичны символы "1" и "0" (да, действительно!), на некоторых языках они полностью несовместимы с числами или любым другим не-строго-булевым типом, а на некоторых языках пустые контейнеры False, в других - True, выбор продолжается). Или посмотрите на nil/null/None, которые также имеют интересные взаимодействия с булевыми и другими вычислениями. Некоторые языки даже могут быть.

Способ, которым Python обрабатывает вставку списка, удобен в некоторых ситуациях, и достаточно людей считают полезным, что они написали код, который использует и зависит от того, как вставлять себя таким образом. Возможно, документация может быть немного яснее, но это действительно не так уж непонятно; и в любом случае, как только вы попробуете его, вы увидите, что он делает, и вы соответственно напишите свой код Python.

Ответ 7

Вместо того, чтобы контрастировать вставку к назначению элемента, она более аналогична назначению среза, так как оба изменяют размер списка.

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

Срезки также не повышают IndexError, и это согласуется с:

a.insert(100, 100)