Используется ли итерационный протокол при индексации объекта диапазона? - PullRequest
0 голосов
/ 22 ноября 2018

Поскольку объект диапазона создает значения по запросу, означает ли это, что каждый раз, когда диапазон индексируется, протокол итерации вызывается до этого индекса?

Что я имею в виду, когда:

>>> R = range(1,11)
>>> print(R[5])
6

Поскольку R[5] не сохраняется в памяти, рассчитывается ли он каждый раз путем создания нового итератора?Если нет, то как можно проиндексировать объект диапазона?

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

Итератор здесь не создается, итерация не происходит.Объект range реализован так, что Python вычисляет значение R[5] по требованию в постоянное время. 1

Если индекс i не отрицательный, вычисление кипитдо:

i * step + start

Так что в случае вашего кода R[5] это будет 5*1 + 1, что равно 6.

Если индекс i отрицателен, длинаR сначала добавляется к i, а затем вычисляется значение, как и раньше:

(i + len(R)) * step + start

Python-internals

Когда вы пишете R[5], этоСинтаксис Python в конечном итоге преобразуется в вызов PyObject_GetItem, который проверяет объект R, чтобы увидеть, как он должен продолжить поиск элемента по индексу 5.

PyObject_GetItem первымпроверяет слот tp_as_mapping типа range.Это не нуль;он содержит ссылку на структуру с именем range_as_mapping.PyObject_GetItem затем проверяет, что находится в mp_subscript поле этой структуры:

static PyMappingMethods range_as_mapping = {
        (lenfunc)range_length,       /* mp_length */
        (binaryfunc)range_subscript, /* mp_subscript */
        (objobjargproc)0,            /* mp_ass_subscript */
};

Как видно из приведенного выше фрагмента, он находит range_subscript функция, занимающая поле mp_subscript. 2

Теперь range_subscript проверяет аргументы, которые были переданы (R и 5), чтобы решить, является ли одинИндекс или фрагмент был запрошен.Целое число 5 означает, что необходим только один индекс, и поэтому функция делегирует вычисление значения compute_range_item.Эта функция выполняет вычисление для возврата целого числа 6, как указано в первой части этого ответа.


1 Я предполагаю, что вы используете CPython: другие реализации Python могут реализовыватьrange объект по-разному.

2 Если вы должны были вызвать len(R), вы можете увидеть внутреннюю функцию в mp_length, которая вызывается для вычисления длины R (см. Почему «1000000000000000 в диапазоне (1000000000000001)» так быстро в Python 3? ).

0 голосов
/ 22 ноября 2018

Неа.Это не так.

Однако range поддерживает протокол итерации и индексирование (через getitem )

...