В любом языке программирования есть специальные инструменты контроля исполнения – эти инструменты позволяют исполнять программу не последовательно, а в каком-то другом порядке. За ветвление обычно отвечают if-else и switch, а за многократное исполнение – циклы. Python предлагает на выбор 2 вида циклов: while и for, каждый лучше подходит под свой тип задачи. Кроме того, в Python цикл for существенно отличается от реализаций for в других языках программирования – об этом, как и в целом о циклах в Python, рассказываем ниже.
Для начала разберемся с циклами как таковыми. Их основная суть – выполнять определенный набор действий, пока истинно некоторое условие. Всего в программировании есть 3 распространенных вида циклов: while, do-while (иногда называют repeat) и for. На блок-схемах они выглядят так:
В чем разница:
Глобальная разница – в том, что while и do-while исполняются неизвестное число раз – «пока не будет выполнено условие». В то же время for используется тогда, когда точно (или достаточно приблизительно) известно, сколько раз нужно отработать циклу – перебор массива, 10 попыток коннекта к удаленному серверу и так далее.
Форма цикла while в Python:
while [условие]:
тело цикла
Для того, чтобы тело цикла исполнялось, условие должно возвращать true. Внутри тела цикла может быть любой код – даже другие циклы. Как это работает на практике:
Цикла do-while в Python нет, поэтому сразу переходим к for. Синтаксис:
for элемент in итерируемый_объект:
тело цикла
For принимает на вход любой итерируемый объект – список, словарь, строку, объект range и так далее. Этот итерируемый объект последовательно перебирается, каждый элемент итерируемого объекта присваивается переменной «элемент», после чего отрабатывает тело цикла:
В других языках программирования циклы for работают по принципу «собери его сам», например – в Golang for будет выглядеть как:
for i := 0; i < 10; i++ {
// тело цикла
}
, то есть мы сами задаем счетчик; в Python «натуральным счетчиком» является количество элементов итерируемого объекта. Это – крайне удобно, когда мы работаем со структурами данных; но что делать, если нам нужен конкретно счетчик – например, мы хотим, чтобы цикл отработал ровно 10 раз?
Для этой задачи в Python есть структура данных range. Она создается через функцию range(), которая принимает 3 параметра:
range([начальное значение,]конечное значение[,шаг])
Параметры в квадратных скобках – опциональные, единственный обязательный параметр – конечное значение. Функция range() возвращает объект-«счетчик», если мы укажем только обязательный параметр – она вернет счетчик, начинающийся с нуля и заканчивающийся числом, на единицу меньшим, чем то, которое мы передали, то есть range(5) вернет счетчик с числами от 0 до 4. [Начальное значение,] позволяет задать, как нетрудно догадаться, начальное значение: range(2,5) вернет счетчик от 2 до 4. Наконец, [,шаг] позволяет вернуть счетчик, в котором числа будут идти с некоторым промежутком – range(3,10,2) вернет счетчик с числами 3, 5, 7 и 9.
Иногда бывает удобно досрочно прервать выполнение цикла – либо только текущую итерацию, либо вообще весь цикл. А в случае с бесконечными циклами единственный способ избежать зависания приложения – это прервать цикл. Для того, чтобы пропустить текущую итерацию, есть ключевое слово «continue»; если нужно полностью прервать цикл, используют ключевое слово «break». Пример с continue:
for i in range(1, 10):
if i % 2 == 0:
continue
print(i)
Цикл выводит только нечетные числа, потому что на каждом четном числе срабатывает if, который содержит в себе continue – и цикл досрочно переходит к следующей итерации.
Пример с break:
for i in range(1, 10):
if i == 5:
break
print(i)
Приложение выведет числа от 1 до 4 – на числе 5 сработает if, который содержит в себе break, и весь цикл остановится.
Из интересных дополнительных инструментов для циклов можно отметить else, pass и короткую запись цикла.
Циклы for и while в Python позволяют добавить после себя необязательную конструкцию else, инструкции в которой отработают после того, как цикл будет закончен. Пример:
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(f"{n} равно {x} * {n // x}")
break
else:
print(f"{n} является простым числом")
Здесь мы используем вложенный цикл для поиска простых чисел, с помощью else во вложенном цикле мы выводим число, если внутренний цикл не нашел делителей. Что важно: else после цикла сработает только в том случае, если цикл завершился «естественным» образом – условие стало false или for пересчитал все элементы. Если же цикл завершился из-за break, return или генерации исключения, блок else исполняться не будет.
Что касается pass – тут все просто. В языках, в которых блоки кода обозначаются специальными символами (чаще всего – {}), мы можем создать пустой цикл:
for i := 0; i < 10; i++ {
}
В Python так не получится – интерпретатор выдаст ошибку. Чтобы «заткнуть» его, нам нужно использовать операцию-пустышку – pass:
for elem in range(10):
pass
Наконец, Python предоставляет синтаксический сахар для генерации последовательностей – генераторы. Обычно генераторы используются для создания списков и кортежей. Генератор представляет собой однострочный цикл, который вмещает действие, перечисление и условие, синтаксис:
[действие] for [переменная] in [итерируемый_объект] if [условие]
Условие – необязательный элемент. Как пример – генератор, создающий список квадратов четных чисел:
even_squares = [x**2 for x in range(1, 11) if x % 2 == 0]
Здесь мы для всех чисел от 1 до 10 (x in range(1, 11)) помещаем в список (генератор обернут в [] скобки) их квадраты (x**2), но – только в том случае, если число x – четное (if x % 2 == 0).
С базовыми применениями циклов (перебор, достижение условия) вы и сами разберетесь, мы же рассмотрим более продвинутые вещи.
Первое, что вам может пригодиться – бесконечный цикл. Они бывают крайне удобны – например, если мы пишем сервер, то мы запускаем внутри него бесконечное ожидание и обработку входящих запросов. С помощью цикла for в Python создать бесконечный цикл нельзя (на самом деле – можно, но не делайте так, такой код будет сложно понять), поэтому остается while:
while True:
#что-то делаем
if [условие]:
break
В бесконечные циклы обязательно нужно добавлять break с условием, при котором цикл будет завершаться – иначе вы потеряете контроль над циклом.
Второй прием – вложенные циклы:
for i in range(10):
# тело внешнего цикла
for j in range(20):
# тело внутреннего цикла
Особенно они полезны, когда вам нужно перебрать матрицу, то есть двухмерный массив. Но помните: каждый новый вложенный цикл умножает количество операций на число, равное количеству его срабатываний, то есть рано или поздно у вас могут кончиться ресурсы железа.
Еще одна техника – имитация do-while в Python. Выглядит вот так:
x = 0
while True:
x += 1
print(x)
if x >= 5:
break
То есть мы создаем бесконечный цикл, внутри которого сначала помещаем тело цикла, а затем – условие и break, если условие будет False. Не очень красиво, зато – работает.
Наконец – помните, что связка for и in позволяет перебирать любые iterable. Например – вот как выглядит перебор словаря:
student_scores = {
'Alice': 85,
'Bob': 92,
'Charlie': 78,
'Diana': 90
}
for student, score in student_scores.items():
print(f"{student}: {score}")
.items() возвращает нам кортеж (ключ, значение), который мы автоматически распаковываем в переменные – с ними уже можно работать.
Тезисно: