Циклы

В прошлой части мы говорили о данных которые собраны в последовательности или группы. Теперь настало время обсудить способ обработать эти данные. Для последовательной обработки данных в Python есть специальные языковые конструкции которые называются циклы. Хотя слово цикл уже вошло в язык, но у английского слова cycle есть перевод который лучше всего объясняет смысл этой конструкции — круговорот. То есть какой-то блок программы последовательно запускается много раз подряд. Цикл устроен следующим образом:

  • Есть точка входа или определения цикла — это место в котором описываются условия повторения и обозначается начало конструкции
  • Обычно в точке цикла находится условие цикла, это проверка которая будет проходить каждый раз когда цикл будет запускаться заново и определяет стоит ли еще раз выполнять тело цикла
  • Тело цикла — это последовательность команд которые надо выполнить
  • После того как тело цикла выполнится программа возвращается к точке входа где проверяется условие цикла

В некоторых языках программирования есть циклы с предусловием и постусловием, в Python есть только циклы с предусловием. И если честно их вполне хватает.

Чтобы было понятно на примере из реального мира представьте, что вы подготавливаете стол к вечеринке и вам надо сделать вкусные бутерброды, если все ингредиенты уже готовы то ваша последовательность будет выглядеть приблизительно так:

Пока есть подготовленные ингредиенты выполнять следующие шаги:
   1. Взять кусочек хлеба из подготовленных
   2. Намазать масло или соус на кусочек хлеба в руке
   3. Положить овощи (если это не сладкий бутерброд)
   4. Положить начинку
   5. Красиво выложить готовый бутерброд на блюдо

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

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

Примеры из реальной жизни:

  • for у вас есть список упражнений домашней работы и надо их сделать все
  • while вы не знаете сколько раз конкретно надо будет взмахнуть лопатой, но вы будете рыть руду в Minecraft пока не наберете нужное количество золото необходимого чтобы сделать новые доспехи

for-циклы

Сейчас мы познакомимся с циклами for. Уникальная особенность цикла заключается в том, что он позволяет по очереди обработать множества и умеет создавать специальные переменные цикла. При каждом прохождении цикла будет браться следующий элемент (или элементы) множества и присваиваться переменной цикла. Лучше всего это объяснить на примере:

1
2
3
4
items = ['apple', 'gold', 'wood']
for i in items:
    # body of the loop
    print(i)

Разберем построчно:

  • Строка 1: Объявляется переменная items, это список, а списки поддерживают возможность итерирования. Вот для чего мы знакомились с коллекциями в прошлой главе.
  • Строка 2: Объявление цикла которое говорит, что надо обработать каждый элемент из в множества items и пока цикл будет проходить по множеству, то он будет брать по очереди элемент и класть его в переменную цикла i (краткое от item).
  • Строка 4: Функция print выводит на печать значение переменной цикла i.

Переменная i меняется после каждого раза когда заканчивается выполнение тела цикла. Вы можете менять ее значение внутри тела как вам хочется, если это, конечно, не усложнит чтение кода. Но каждый раз когда тело цикла и код вернется к началу цикла то ей будет присвоено новое значение.

В общем случае синтаксис for-цикла выглядит так:

for <переменная> in <итератор>:
    <тело цикла>

Работа с типами с помощью цикла for

Если итератор возвращает несколько значений, например кортеж состоящий из 2 элементов, то можно объявить сразу несколько переменных цикла. Это прекрасно работает со словарями или функцией enumerate:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
guild = {
    "Codex": "Priest",
    "Zaboo": "Warlock",
    "Vork": "Warrior",
    "Bladezz": "Rogue",
    "Clara": "Mage",
    "Tinkerballa": "Ranger",
}

for nickname, role in guild.items():
    print(f"{nickname} is {role}")

Вызов guild.items() возвращает список состоящий из кортежей из двух элементов которые раскрываются в переменные nickname и role.

>>> guild.items()
dict_items([('Codex', 'Priest'), ('Zaboo', 'Warlock'), ('Vork', 'Warrior'),
('Bladezz', 'Rogue'), ('Clara', 'Mage'), ('Tinkerballa', 'Ranger')])

enumerate подходит для тех случаев когда надо пройтись по элементам и пронумеровать их:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
guild = {
    "Codex": "Priest",
    "Zaboo": "Warlock",
    "Vork": "Warrior",
    "Bladezz": "Rogue",
    "Clara": "Mage",
    "Tinkerballa": "Ranger",
}

for number, name in enumerate(guild.keys(), start=1):
    print(f"{number}. {name}")

Выражение в строке 10 получает список ключей словаря, и создает из них последовательность состоящую из кортежей из двух элементов где первый это номер созданый функцией, а второй ключ словаря:

>>> list(enumerate(guild.keys(), start=1))
[(1, 'Codex'), (2, 'Zaboo'), (3, 'Vork'), (4, 'Bladezz'),
(5, 'Clara'), (6, 'Tinkerballa')]

Если просто необходимо сделать определенное количество повторов (итераций) цикла, то прекрасно подходит уже известная функция range:

>>> for i in range(1, 6):
...     print("Повтор", i)
...
Повтор 1
Повтор 2
Повтор 3
Повтор 4
Повтор 5

Можно так же последовательно обрабатывать строки, потому что строка тоже итератор:

>>> for n, c in enumerate("Python", 1):
...     print(n, c)
...
1 P
2 y
3 t
4 h
5 o
6 n

И все остальные типы множеств: кортежи (tuple), множества (set и frozenset), списки (list), строки (str).

Циклы for и генераторы

Вы наверное обратили внимание, что ключевое слово for используется и в формате записи генераторов списков и при создании циклов. Все верно, хотя это немного разные конструкции, но чтобы отличать их давайте еще раз их сравним.

Цикл:

for item in items:
    process(item)

Генератор списка:

[process(item) for item in items]

В чем же разница? На самом деле она существенная:

  • Генераторы служат для того чтобы создавать новые множества: списки или словари;
  • Генераторы имеют компатную запись и не позволяют совершать множество операций над элементами множества;
  • Циклы могут иметь большое тело цикла;
  • Тело цикла не обязательно должно возвращать элементы, вполне нормальная ситуация когда вы вывели переменную цикла на экран и больше ничего не сделали;

Сравните код генератора списков и обычного цикла. Все примеры создают список квадратов чисел от 0 до 10:

# с помощью циклов
result = []

for i in range(11):
    result.append(i**2)

# с помощью генератора списков
result = [i**2 for i in range(11)]

# или создание итератора, который будет создавать следующее значение в тот момент когда к нему обращаются
result = (i**2 for i in range(11))

Цикл while

Цикл while работает совершенно по другому, он не пытается создавать переменные цикла (но вы можете создавать их сами внутри тела цикла), а работает до тех пор пока выполняется условие цикла, то есть оно равно True. Общая форма записи цикла:

while <условие>:
    <тело цикла>

Обратите внимание, что точно так же как и во всех блоковых структурах тело цикла выделяется отступами в 4 пробела.

Пример использования цикла:

1
2
3
4
5
6
7
8
9
# Этот код складывает числа от 1 до 5 и выводит результат
n = 5
i = 1
result = 0
while i <= n:
    result = result + i
    i = i+1  # увеличиваем значение счетчика

print("Результат:", result)

Условие в строке 5 проверяется после каждого выполнения тела цикла. Когда программа доходит до строки 7, то возвращается к строке 5 и проверяет условие. Если оно выполняется, то цикл выполняется еще раз.

Если необходимо сделать цикл который будет выполняться бесконечно, то в условие можно вставить любое выражение которое будет равно True. И лучше всего с этой ролью справляется само True:

while True:
    print("+")

Остановка выполнения программы

Если вы запустили этот код, то можете его прекратить нажав CtrlC. Это способ прекратить выполнение любой программы. Для выхода из интерактивного режима Python нажмите CtrlD.

Управление выполнением циклов

Не всегда имеет смысл ждать выполнение цикла до конца, например если вы в цикле проверяли данные, и нашли искомое. Для того чтобы продолжить выполнение кода или выйти из цикла полностью есть два оператора continue и break.

Оператор continue

Если вы хотите прекратить выполнение текущего тела цикла и вернуться к точке входа, то используйте continue:

>>> for i in range(10):
...     if i % 2 ==0:
...         continue
...     print(i)
...
1
3
5
7
9

Этот код проверяет делится ли i без остатка на 2 и если да, то прекращает выполнение текущего тела цикла и возвращает выполнение программы к началу цикла.

Оператор break

Если вы хотите полностью прекратить работу цикла и выйти из него, то воспользуйтесь оператором break.

1
2
3
4
5
6
7
8
import random
n = random.randint(0, 10)
print("Отгадайе число от 0 до 10")
while True:
    x = int(input("Введите вариант: "))
    if x == n:
        print("Правильно!")
        break

Выполнение этого кода создаст переменную n и присвоит ей случайно число от 0 до 10 и будет спрашивать пользоваетеля до тех пор пока он не угадает число. Работу конструкции if-else мы выучим на следующем уроке.

else

Если вам надо проверить произошел ли выход из цикла досрочно с использованием break или был закончен ествественным образом то есть возможность использовать специальную else конструкцию. Она работает и с for и с while циклами. Если в процессе работы цикла произошел вызов break то она не исполнится. В некоторых случаях это может существенно сэкономить время на дополнительных проверках.

Пример использования:

1
2
3
4
5
6
7
s = input("Введите строку без цифр: ")
for i in s:
    if i.isnumeric():
        print("Стоп, найдена цифра ", i)
        break
else:
    print("Ввели правильно")

Ссылки