Когда я преподаю кому-то программирование (практически на любом языке), я представляю for
циклы с терминологией, подобной этому примеру кода:
for eachItem in someList:
doSomething(eachItem)
... что, достаточно удобно, является синтаксически допустимым кодом Python.
Функция Python range()
просто возвращает или генерирует список целых чисел от некоторой нижней границы (ноль, по умолчанию) до (но не включая) некоторой верхней границы, возможно, в приращениях (шагах) некоторого другого числа (один по умолчанию).
То есть range(5)
возвращает (или, возможно, генерирует ) последовательность: 0, 1, 2, 3, 4 (до верхней границы, но не включая ее).
Вызов range(2,10)
вернет: 2, 3, 4, 5, 6, 7, 8, 9
Вызов range(2,12,3)
вернет: 2, 5, 8, 11
Обратите внимание, что я пару раз говорил, что функция range()
Python возвращает или генерирует последовательность. Это относительно продвинутое различие, которое обычно не будет проблемой для новичка. В старых версиях Python range()
создавал список (выделил для него память и заполнял значениями) и возвращал ссылку на этот список. Это может быть неэффективно для больших диапазонов, которые могут потреблять совсем немного памяти, а также для некоторых ситуаций, когда вы можете захотеть перебрать некоторый потенциально большой диапазон чисел, но, скорее всего, "break
" из Ранний цикл (например, после нахождения какого-то конкретного элемента, который вас заинтересовал).
Python поддерживает более эффективные способы реализации одной и той же семантики (выполнения одной и той же вещи) с помощью программной конструкции, называемой generator . Вместо того, чтобы выделять и заполнять весь список и возвращать его как статическую структуру данных, Python может создать экземпляр объекта с необходимой информацией (верхняя и нижняя границы и значение шага / приращения) ... и вернуть ссылку на него. Затем объект отслеживает, какое число он вернул в последний раз, и вычисляет новые значения, пока не достигнет верхней границы (и в какой точке он сигнализирует об окончании последовательности вызывающей стороне, используя исключение под названием «StopIteration»). Этот метод (вычисление значений динамически, а не все сразу, заранее) называется «отложенной оценкой».
Другие конструкции в языке (например, те, что лежат в основе цикла for
) могут затем работать с этим объектом, как если бы это был список.
В большинстве случаев вам не нужно знать, использует ли ваша версия Python старую реализацию range()
или более новую, основанную на генераторах. Вы можете просто использовать это и быть счастливым. Если вы работаете с диапазонами миллионов элементов или создаете тысячи различных диапазонов по тысячи единиц, вы можете заметить снижение производительности за использование range()
в старой версии Python. В таких случаях вы можете переосмыслить свой дизайн и использовать циклы while
, или создать объекты, которые реализуют семантику «ленивой оценки» генератора, или использовать xrange()
версию range()
, если ваша версия Python включает ее или range()
функция из версии Python, которая неявно использует генераторы.
Такие понятия, как генераторы и более общие формы ленивых вычислений, пронизывают программирование на Python по мере того, как вы выходите за рамки основ. Обычно это вещи, которые вам не нужно знать для простых задач программирования, но они становятся важными, когда вы пытаетесь работать с большими наборами данных или в рамках более жестких ограничений (например, времени / производительности или ограничений памяти).