Как реализуется список Python?

Это связанный список, массив? Я искал вокруг и только нашел, что люди догадываются. Мои знания C недостаточно хороши, чтобы посмотреть исходный код.

119
задан Greg 12 окт. '10 в 20:56
источник поделиться
7 ответов

Это динамический массив. Практическое доказательство. Индексирование происходит (конечно, с крайне небольшими различиями (0,0013 мкс!)) В то же время независимо от индекса:

...>python -m timeit --setup="x = [None]*1000" "x[500]"
10000000 loops, best of 3: 0.0579 usec per loop

...>python -m timeit --setup="x = [None]*1000" "x[0]"
10000000 loops, best of 3: 0.0566 usec per loop

Я был бы поражен, если бы IronPython или Jython использовали связанные списки - они бы разрушили производительность многих многих широко используемых библиотек, построенных на предположении, что списки представляют собой динамические массивы.

40
ответ дан user395760 12 окт. '10 в 21:04
источник поделиться

На самом деле код C довольно прост. Развернув один макрос и обрезая некоторые несущественные комментарии, базовая структура находится в listobject.h, которая определяет список как:

typedef struct {
    PyObject_HEAD
    Py_ssize_t ob_size;

    /* Vector of pointers to list elements.  list[0] is ob_item[0], etc. */
    PyObject **ob_item;

    /* ob_item contains space for 'allocated' elements.  The number
     * currently in use is ob_size.
     * Invariants:
     *     0 <= ob_size <= allocated
     *     len(list) == ob_size
     *     ob_item == NULL implies ob_size == allocated == 0
     */
    Py_ssize_t allocated;
} PyListObject;

PyObject_HEAD содержит счетчик ссылок и идентификатор типа. Таким образом, это вектор/массив, который объединяется. Код для изменения размера массива, когда он заполнен, находится в listobject.c. Он фактически не удваивает массив, а растет, выделяя

new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);
new_allocated += newsize;

в каждый раз, где newsize - запрошенный размер (необязательно allocated + 1, потому что вы можете extend произвольным числом элементов вместо append 'их по одному).

См. также Часто задаваемые вопросы по Python.

181
ответ дан Fred Foo 18 окт. '10 в 13:39
источник поделиться

В CPython списки представляют собой массивы указателей. Другие реализации Python могут выбирать их по-разному.

27
ответ дан Amber 12 окт. '10 в 21:00
источник поделиться

Это зависит от реализации, но IIRC:

  • CPython использует массив указателей
  • Jython использует ArrayList
  • IronPython, по-видимому, также использует массив. Вы можете найти исходный код, чтобы узнать.

Таким образом, они имеют O (1) случайный доступ.

24
ответ дан NullUserException 12 окт. '10 в 20:59
источник поделиться

В соответствии с документация,

Списки Pythons представляют собой массивы переменной длины, а не Lisp -строчные связанные списки.

22
ответ дан ravi77o 01 июня '12 в 18:07
источник поделиться

Я бы предложил статью Лорана Люса "Реализация списка Python" . Был действительно полезен для меня, потому что автор объясняет, как список реализован в CPython и использует для этой цели отличные диаграммы.

Структура списка объектов C

Объект списка в CPython представлен следующей структурой C. ob_item - это список указателей на элементы списка. выделенное количество слотов, выделенных в памяти.

typedef struct {

PyObject_VAR_HEAD

PyObject ** ob_item;

выделен Py_ssize_t;

} PyListObject;

Важно заметить разницу между выделенными слотами и размером списка. Размер списка совпадает с размером len (l). Количество выделенных слотов - это то, что было выделено в памяти. Часто вы увидите, что выделенное может быть больше размера. Это делается для того, чтобы избежать необходимости вызова realloc каждый раз, когда к списку добавляются новые элементы.

...

Append

Мы добавляем целое число в список: l.append(1). Что происходит?
введите описание изображения здесь

Продолжаем добавление еще одного элемента: l.append(2). list_resize вызывается с n + 1 = 2, но поскольку выделенный размер равен 4, нет необходимости выделять больше памяти. То же самое происходит, когда мы добавляем еще 2 целых числа: l.append(3), l.append(4). Следующая диаграмма показывает, что у нас есть.

введите описание изображения здесь

...

Вставить

Позволяет вставить новое целое число (5) в позицию 1: l.insert(1,5) и посмотреть, что происходит внутри. введите описание изображения здесь

...

Поп

При нажатии последнего элемента: l.pop() вызывается listpop(). list_resize вызывается внутри listpop(), и если новый размер меньше половины выделенного размера, тогда список сокращается. введите описание изображения здесь

Вы можете заметить, что слот 4 все еще указывает на целое число, но главное - это размер списка, который теперь равен 4. Позволяет добавить еще один элемент. В list_resize() размер - 1 = 4 - 1 = 3 меньше половины выделенных слотов, поэтому список сокращается до 6 слотов, а новый размер списка теперь равен 3.

Вы можете заметить, что слот 3 и 4 по-прежнему указывают на некоторые целые числа, но главное - это размер списка, который теперь равен 3. введите описание изображения здесь

...

УдалитьУ объекта списка Python есть метод для удаления определенного элемента: l.remove(5). введите описание изображения здесь

9
ответ дан Lesya 20 июля '17 в 13:50
источник поделиться

Как уже отмечалось выше, списки (когда значительно большие) реализуются путем выделения фиксированного количества пространства и, если это пространство должно заполняться, выделяя больший объем пространства и копируя элементы.

Чтобы понять, почему метод O (1) амортизирован, не ограничивая общности, предположим, что мы вставили a = 2 ^ n элементов, и теперь нам нужно удвоить нашу таблицу до 2 ^ (n + 1). Это означает, что мы в настоящее время выполняем операции 2 ^ (n + 1). Последняя копия, мы сделали 2 ^ n операций. До этого мы сделали 2 ^ (n-1)... вплоть до 8,4,2,1. Теперь, если мы добавим их, получим 1 + 2 + 4 + 8 +... + 2 ^ (n + 1) = 2 ^ (n + 2) - 1 < 4 * 2 ^ n = O (2 ^ n) = O (a) суммарные вставки (то есть O (1) амортизированное время). Кроме того, следует отметить, что если таблица позволяет удалять, сокращение таблицы должно выполняться с другим фактором (например, 3 раза)

5
ответ дан RussellStewart 22 окт. '13 в 6:00
источник поделиться

Другие вопросы по меткам