Инструкция цикла for

В случаях когда в программе инструкции должны повторяться определенное кол-во раз и при этом некая величина должна меняться с постоянным шагом применяют инструкцию for.

Пример: Указан интервал, например от 1 до 7 (включительно), вывести все числа в консоль, для всех чисел которые делятся на 3 без остатка вывести сообщение.

Решение:
print(1)
print(2)
print(3, "Делится на 3 без остатка")
# ...
print(6, "Делится на 3 без остатка")
print(7)
Данное решение прямо намекает что все решение можно организовать циклически, а сам факт того что кол-во итераций известно и на каждом шагу изменяется некая величина на фиксированное значение (шаг) говорит что следует использовать инструкцию цикла for:
numbers = [1, 2, 3, 4, 5, 6, 7]
for number in numbers:
    result = str(number)
    if number % 3 == 0:
        result += ' Делится на 3 без остатка'
    print(result)
Цикл for очень часто используется для итерирования по перечисляемым коллекциям, в примере происходит проход по списку значений, где на каждом шаге цикла переменная цикла "number" принимает следующе значение последовательности, до тех пор пока она не будет исчерапана.
Структура инструкции:

for < переменная цикла > in < объект последовательность >:
< блок инструкций >

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

  • Переменная цикла доступна только в области блока инструкции (локальная переменная).
  • После выхода из цикла эта переменная обычно все еще ссылается на последний элемент последовательности, если цикл не был завершен инструкцией break.
  • Инструкция for также поддерживает необязательную часть else, которая работает точно так же, как и в циклах while, – она выполняется, если выход из цикла производится не инструкцией break.

Полная структура цикла for имеет следующий вид:

for < переменная цикла > in < объект последовательность >:
if < выражение условие 1>:
break
elif < выражение условие 2>:
continue else:
pass
else: < блок инструкций else >
Функция range
Функция возвращает набор целых чисел(целочисленный итератор), образующий арифметическую прогрессию. Например, если нужно получить числа 0, 1, 2, ..., 7, то следует оформить вызов функции: range(8). *Обратите внимание что функция не возвращает список элементов, она возвращает итератор (итераторы будут рассмотрены в отдельной главе).
Вы будете часто использовать функцию совместно с циклом for.

Рассмотрим фунцию и ее аргументы подробно:

range([start,] stop [,step])

  • start - значение первого элемента, по умолчанию 0;
  • stop - значение конца последовательности (не включено), обязательный аргумент;
  • step - шаг, на который каждый элемент больше предыдущего, по умолчанию 1.
Рассмотрим примеры использования функции:
# Зададим только конец последовательности
end = 5
for i in range(end):
    print(i) # 0, 1, 2, 3, 4
# Зададим начало и конец последовательности
start = 1
end = 5
for i in range(start, end):
    print(i) # 1, 2, 3, 4
Рассмотрим предыдущую задачу с использованием фунции range:
start = int(input())
end = int(input())
for i in range(start, end):
    result = str(i)
    if i % 3 == 0:
        result += ' Делится на 3 без остатка'
    print(result)
Функция enumerate
Эта функция схожа с range по области применения и так же часто используются с циклом for. Рассмотрим на примере: Необходимо проитерировать по списку элементов и вывести в консоль значение индекса и значение элемента, если он не равен NULL. Ранее нам приходилось иметь дело либо только с индексами, либо только с элементами. Для того чтобы иметь в теле цикла и индекс и значение следует использовать следующий вариант функции range:
elements = ['first', None, 'third']
for i in range(len(elements)):
    if elements[i] is not None:
        print('Индекс: ', i, 'элемент: ', elements[i])
Функция len(iterable), возвращает кол-во элементов последовательности.
Такой способ организации цикла является обычной практикой, но функция enumerate позволяет снизить визуальный шум:

enumerate(iterable, [start])

Используется при итерации в циклах for чтобы получать одновременно и элемент и индекс элемента в виде кортежа (index, elem). Значение индекса начинается с start, если не задано то с 0.

Рассмотрим предыдущий пример с использованием функции enumerate:
elements = ['first', None, 'third']
for i, elem in enumerate(elements):
    if elem is not None:
        print('Индекс: ', i, 'элемент: ', elem)
Очевидно читабильность кода заметно повышается, даже на таком простом примере, это в стиле философии Python.
Функция zip
Функция гораздо реже используется, но ее полезность трудно переоценить.
Рассмотрим задачу:

Есть упорядоченный список названий цветов и есть список их hex-кодов, в цикле нужно вывести на экран пару: "Название цвета: hex-код".

Классическое решение через range будет выглядеть вот так:
names = ['red', 'orange', 'blue']
hexes = ['#a83232', '#ff9100', '#00aaff']
for i in range(len(names)):
    print(names[i], ': ', hexes[i])
Это решение рабочее, но есть недостатки этого способа:

  • Количество визуального шума, из-за манипулирования с индексами снова снижает читаемость кода.
  • Если длинна списков будет различной, то мы получим исключение IndexError, либо нужно делать обработку исключения, либо контролировать чтобы во втором списке элементов было не меньше чем в первом, это добавит еще больше инструкций в код и снизит его читабельность.
Для таких ситуаций нужно использовать функцию zip.

zip(iterable_1, iterable_2, …, iterable_n)

Позволяет пройтись одновременно по нескольким последовательностям. Функция zip возвращает итератор, который останавливается, когда исчерпывается самая короткая последовательность.

Рассмотрим наш пример с использованием zip, обратите внимание что в списке имен цветов теперь больше элементов, но это не вызовет ошибки, элемент которому не досталась "пара", будет проигнорирован:
names = ['red', 'orange', 'blue', 'black']
hexes = ['#a83232', '#ff9100', '#00aaff']
for name, hex in zip(names, hexes):
    print(name,': ', hex)