Все курсы > Программирование на Питоне > Занятие 3
На шестом занятии вводного курса ML мы уже начали изучать условия и циклы. Продолжим этот путь.
Вначале откроем ноутбук к этому занятию⧉
Еще раз про условия с if
Помимо базовой уже известной нам структуры if-else, мы также можем прописать несколько условий (multi-way decisions) с помощью if-elif-else. Слово elif в данном случае как раз и позволяет добавить новые условия.
Например, мы хотим написать программу, которая разделит все передаваемые ей числа на малые (small), средние (medium) и большие (large). Сначала посмотрим на блок-схему.

Если слово меньше 10, то оно малое, меньше 100 — среднее, в противном случае оно большое. Теперь пропишем это на Питоне.
1 2 3 4 5 6 7 8 9 |
x = 42 # зададим число # и пропишем условия (не забывайте про двоеточие и отступ) if x < 10: print('Small') elif x < 100: print('Medium') else: print('Large') |
1 |
Medium |
До сих пор мы записывали число или строку в переменную. Пора познакомиться с возможностью ввода числа с клавиатуры. В этом нам поможет встроенная в Питон функция input(). В частности, описанная выше программа могла бы запрашивать число у пользователя, а уже потом классифицировать.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# запросим число у пользователя x = input('Введите число: ') # преобразуем в тип int x = int(x) # и наконец классифицируем if x < 10: print('Small') elif x < 100: print('Medium') else: print('Large') |
При исполнении этого кода вначале появляется поле для ввода.

После ввода числа и нажатия клавиши Enter, мы получаем результат.
1 2 |
Введите число: 42 Medium |
Обратите внимание на два момента. Во-первых, внутри функции input() в кавычках мы пишем сообщение, которое увидит пользователь. Во-вторых, любые введенные нами символы воспринимаются как тип str (string, строка). Соответственно, если мы хотим, чтобы ввод считался числом, сначала нужно его преобразовать с помощью функции int().
Помимо этого, одно условие может быть вложено в другое (nested decisions). Приведем пример.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# запрашиваем число y = input('Введите число: ') # проверяем первое условие (не пустая ли строка), если оно выполняется if len(y) != 0: # преобразуем в тип int y = int(y) # и классифицируем if x < 10: print('Small') elif x < 100: print('Medium') else: print('Large') # в противном, говорим, что ввод пустой else: print('Ввод пустой') |
Если ввести число, то алгоритм продолжит классификацию.
1 2 |
Введите число: 42 Medium |
В противном случае, оставив ввод пустым и нажав Enter, классификация будет опущена и мы получим следующее сообщение.
1 2 |
Введите число: Ввод пустой |
В коде можно прописать сразу несколько условий в одном выражении. Например, можно объединить if c логическими операторами and или or. Вначале приведу пример с логическим И.
1 2 3 4 5 6 7 8 9 10 11 |
z = 42 # если z больше 10 и одновременно меньше 100 if z > 10 and z < 100: # у нас среднее число print('Medium') # в противном случае оно либо маленькое либо большое else: print('Small or Large') |
1 |
Medium |
А также логическим ИЛИ.
1 2 3 4 5 6 7 8 9 10 11 |
z = 2 # если z меньше 10 или больше 100 if z < 10 or z > 100: # оно либо маленькое либо большое print('Small or Large') # в противном случае оно среднее else: print('Medium') |
1 |
Small or Large |
С помощью if мы можем проверить, входит ли элемент в состав какого-либо объекта или нет. Для этого используются операторы in и not in.
- Оператор in возвращает True, если элемент входит в объект
- Оператор not in возвращает True, если элемент не входит в объект
Посмотрим на примерах.
1 2 3 4 5 6 |
# можно проверить вхождение слова в строку sentence = 'To be, or not to be, that is the question' word = 'question' if word in sentence: print('Слово найдено') |
1 |
Слово найдено |
1 2 3 4 5 6 |
# или отсутствие элемента в списке number_list = [2, 3, 4, 6, 7] number = 5 if number not in number_list: print('Такого числа в списке нет') |
1 |
Такого числа в списке нет |
Еще раз обращу ваше внимание на то, что not in возвращает True, когда элемента НЕТ в объекте. Именно поэтому в примере со списком условие после if выполнилось.
Применим оператор in к словарю.
1 2 |
# возьмем очень простой словарь d = {'apple' : 3, 'tomato' : 6, 'carrot' : 2} |
1 2 3 |
# вначале поищем яблоки среди ключей словаря if 'apple' in d: print('Нашлись') |
1 |
Нашлись |
1 2 3 4 |
# а затем посмотрим, нет ли числа 6 среди его значений # с помощью метода .values() if 6 in d.values(): print('Есть') |
1 |
Есть |
Теперь давайте поговорим про циклы.
Циклы

Цикл for
С циклом for (for loop) мы уже знакомы. Повторим пройденное на несложном примере.
1 2 3 4 5 6 |
# поочередно выведем элементы списка number_list = [1, 2, 3] # не забывая про двоеточие и отступ for number in number_list: print(number) |
1 2 3 |
1 2 3 |
Мы также умеем выводить элементы словаря.
1 2 3 4 5 6 |
# создадим словарь, значениями которого будут списки из двух элементов d = {'apple' : [3, 'kg'], 'tomato' : [6, 'pcs'], 'carrot' : [2, 'kg']} # затем создадим две переменные-контейнера и применим метод .items() for k, v in d.items(): print(k, v) |
1 2 3 |
apple [3, 'kg'] tomato [6, 'pcs'] carrot [2, 'kg'] |
Помимо этого мы можем вывести только ключи или только значения с помощью методов .keys() и .values() соответственно.
Предположим, что мы хотим вывести только числа (первый элемент значения словаря).
1 2 3 4 |
# возьмем только одну переменную и применим метод .values() for v in d.values(): # значение представляет собой список, выведем его первый элемент с индексом [0] print(v[0]) |
1 2 3 |
3 6 2 |
Цикл for можно применить к массиву Numpy.
1 2 3 4 5 6 7 8 9 |
# импортируем библиотеку numpy import numpy as np # создадим массив и поместим в переменную number_array number_array = np.array([1, 2, 3]) # пройдемся по нему с помощью цикла for for number in number_array: print(number) |
1 2 3 |
1 2 3 |
Помимо этого мы можем вложить один цикл for в другой (nested for loops). Предположим, что у нас есть следующая база данных клиентов.
1 2 |
clients = {1: {'name': 'Анна', 'age': 24, 'sex': 'male', 'revenue': 12000}, 2: {'name': 'Илья', 'age': 18, 'sex': 'female', 'revenue': 8000}} |
База данных представляет собой словарь. Ключами являются id клиентов. Значениями — еще один (вложенный) словарь с информацией о каждом клиенте.
Ключами второго (вложенного) словаря выступают названия полей (ФИО, возраст, пол и выручка с клиента), а значениями — соответствующая информация. Выведем все эти данные.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# в первом цикле for поместим id и информацию о клиентах в переменные id и info for id, info in clients.items(): # выведем id клиента print('client ID: ' + str(id)) # во втором цикле возьмем информацию об очередном клиенте (тоже словарь) for k, v in info.items(): # и выведем каждый ключ (название поля) и значение (саму информацию) print(k + ': ' + str(v)) # добавим пустую строку после того, как выведем информацию об одном клиенте print() |
1 2 3 4 5 6 7 8 9 10 11 |
client ID: 1 name: Анна age: 24 sex: male revenue: 12000 client ID: 2 name: Илья age: 18 sex: female revenue: 8000 |
Два комментария.
- Обратите особое внимание на отступы слева, они указывают на очередность выполнения операций. Например, пустая команда print() (и соответственно пустая строка) имеет один отступ, чтобы исполниться после каждого клиента, а не после каждого поля с информацией о клиенте.
- При использовании функции print() мы можем объединить несколько строк, а вот объединить строку и число нельзя. Так как id, значение возраста (age) и значение выручки (revenue) являются числами (тип int), их нужно сначала принудительно сделать строкой через функцию str().
Функции range() и enumerate()
Иногда нам нужно создать последовательность чисел и пройтись по ней в цикле. Конечно, можно создать список и заполнить его нужными элементами, но, во-первых, для этого надо написать много кода, во-вторых, это будет неэффективно с точки зрения памяти компьютера. Для этого есть специальная функция range().
Приведем несколько примеров.
1 2 3 |
# создадим последовательность от 0 до 4 for i in range(5): print(i) |
1 2 3 4 5 |
0 1 2 3 4 |
1 2 3 |
# от 1 до 5 for i in range(1, 6): print(i) |
1 2 3 4 5 |
1 2 3 4 5 |
1 2 3 |
# и от 0 до 5 с шагом 2 (то есть будем выводить числа через одно) for i in range(0, 6, 2): print(i) |
1 2 3 |
0 2 4 |
Теперь рассмотрим, как мы получили такие результаты более детально.


Функция range() принимает от одного до трех параметров.
- Если передать только один параметр, то мы начнем последовательность с нуля и закончим на элементе, предшествующем нашему параметру. В примере выше мы передали параметр «пять» (range(5)) и получили последовательность 0, 1, 2, 3, 4.
- Если указать два параметра, то мы начнем последовательность с первого параметра и законим на элементе, предшествующем второму параметру. В частности, если написать range(1, 6), то получится 1, 2, 3, 4, 5.
- Третий параметр устанавливает шаг. По умолчанию он равен единице, однако если, например, написать, range(0, 6, 2), то мы получим 0, 2, 4.
Что интересно, если совместить range() с функцией len(), то такую конструкцию можно использовать для того, чтобы в одном цикле вывести все элементы, например, двух списков по их индексу.
1 2 3 4 5 6 7 8 9 10 11 |
# возьмем месяцы года months = ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'] # и продажи мороженого в тыс. рублей в каждый из месяцев sales = [47, 75, 79, 94, 123, 209, 233, 214, 197, 130, 87, 55] # задав последовательность через range(len()) for i in range(len(months)): # мы можем вывести каждый из элементов обоих списков в одном цикле print(months[i], sales[i]) |
1 2 3 4 5 6 7 8 9 10 11 12 |
Январь 47 Февраль 75 Март 79 Апрель 94 Май 123 Июнь 209 Июль 233 Август 214 Сентябрь 197 Октябрь 130 Ноябрь 87 Декабрь 55 |
Мы уже применяли эту функцию. На занятии по кластеризации, в методе k-средних мы пробовали разное количество кластеров и смотрели как изменится ошибка модели. Эта функция также использовалась нами при создании рекомендательной системы и в модели экспоненциального сглаживания.
Еще раз посмотрите код прошлых уроков, это будет полезным упражнением.
В целом, если вы хотите найти какой-либо код на этом сайте, воспользуйтесь поиском по сайту (иконка лупы).
Теперь давайте посмотрим на функцию enumerate(). Мы можем использовать эту функцию, если у нас есть, например, список и, проходясь в цикле по этому списку, мы хотим также получить порядковый номер (индекс) элементов списка.
1 2 3 4 5 6 |
# пусть дан список со днями недели days = ['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье'] # выведем индекс (i) и сами элементы списка (day) for i, day in enumerate(days): print(i, day) |
1 2 3 4 5 6 7 |
0 Понедельник 1 Вторник 2 Среда 3 Четверг 4 Пятница 5 Суббота 6 Воскресенье |
Все бы хорошо, но неделю логичнее начинать с первого дня, а не с нулевого. Для этого функции enumerate() можно передать начальное значение.
1 2 3 |
# так же выведем индекс и элементы списка, но начнем с 1 for i, day in enumerate(days, 1): print(i, day) |
1 2 3 4 5 6 7 |
1 Понедельник 2 Вторник 3 Среда 4 Четверг 5 Пятница 6 Суббота 7 Воскресенье |
Эту функцию мы уже применяли на занятии по компьютерному зрению и обработке естественного языка.
Цикл while
С циклом while (while loop) мы пока не знакомы. Как уже было сказано, цикл выполняется пока верно прописанное в нем условие.

В целом все просто, но есть один нюанс.
Условие должно в какой-то момент перестать быть верным, иначе цикл станет бесконечным. Для этого существует счетчик (counter).
Посмотрим как это можно реализовать на Питоне.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# зададим начальное значение счетчика i = 0 # пока счетчик меньше трех while i < 3: # в каждом цикле будем выводить его текущее значение print('Текущее значение счетчика: ' + str(i)) # внутри цикла не забудем "нарастить" счетчик i = i + 1 # и выведем новое значение print('Новое значение счетчика: ' + str(i)) # добавим пустую строку print() |
1 2 3 4 5 6 7 8 |
Текущее значение счетчика: 0 Новое значение счетчика: 1 Текущее значение счетчика: 1 Новое значение счетчика: 2 Текущее значение счетчика: 2 Новое значение счетчика: 3 |
Рассмотрим еще раз, как мы получили такой результат.
- У нас есть начальное значение счетчика, равное нулю (i = 0) (хотя конечно значение счетчика может быть любым)
- При первой итерации, так как 0 < 3, исполняем код в цикле и увеличиваем счетчик на 1 (теперь i = 1)
- На второй итерации, 1 < 3, условие по-прежнему верно, снова исполняем код и увеличиваем счетчик на 1 (i = 2)
- На третьей итерации, 2 < 3, условие верно, исполняем код и увеличиваем счетчик на 1 (i = 3)
- Далее, алгоритм пытается выполнить четвертую итерацию цикла, однако так как 3 < 3 неверно, цикл прерывается
Небольшой лайфхак. Вместо того, чтобы писать i = i + 1 Питон позволяет использовать короткую запись: i += 1.
1 2 3 4 5 |
i = 0 while i < 3: print(i) i += 1 |
1 2 3 |
0 1 2 |
Оператор += увеличивает значение переменной и одновременно присваивает ей это новое увеличенное значение. Короткая запись также применяется к операциям вычитания ( -=), умножения ( *=) и деления ( /=).
Операторы break и continue
Ходом исполнения цикла можно управлять.
Оператор break
Представьте, что вы пишете цикл, который затем примените к очень длинному словарю или списку (в нем, например, 10 тыс. элементов), но вы не уверены в своем коде. Если цикл применить сразу ко всему объекту и при этом окажется, что код делает не совсем то, что вы хотите, то придется ждать, пока компьютер выведет все 10 тыс. записей.
Логично протестировать код на первой записи, а уже потом двигаться дальше. В этом нам поможет оператор break (прерывание цикла).
1 2 3 4 5 6 7 8 9 10 11 12 |
# вновь возьмем словарь clients clients = {1: {'name': 'Анна', 'age': 24, 'sex': 'male', 'revenue': 12000}, 2: {'name': 'Илья', 'age': 18, 'sex': 'female', 'revenue': 8000}} # в цикле пройдемся по ключам и значениям словаря for id, info in clients.items(): # и выведем их print(id, info) # однако уже после первого исполнения цикла, прервем его break |
1 |
1 {'name': 'Анна', 'age': 24, 'sex': 'male', 'revenue': 12000} |
Цикл можно также прерывать при наступлении определенного условия.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# зададим начальное значение счетчика x = 6 # будем исполнять цикл пока x не равен нулю while x != 0: # выведем текущее значение счетчика print(x) # и уменьшим (!) его на 1 x -= 1 # если значение счетчика станет равным 3, прервем цикл if x == 3: break |
1 2 3 |
6 5 4 |
Мы прервали цикл, когда значение счетчика стало равно трем.
Также обратите внимание, что здесь цикл двигается в сторону уменьшения (с помощью -=). Мы начали с x = 6 и должны были вывести значения 6, 5, 4, 3, 2, 1, если бы условие не прервало выполнение цикла.
Оператор continue
Иногда цикл не нужно прерывать, но нужно как бы «перескочить» одну или несколько итераций этого цикла. В этом случае применяется оператор continue.
Предположим, нам нужно создать последовательность целых чисел от 1 до 10 включительно и вывести только четные числа.
Как мы помним, четное число — это число, которое делится на два без остатка.
Последовательность создавать мы умеем. Взятие остатка от деления мы уже рассмотрели на прошлом занятии. Осталось написать код целиком.
1 2 3 4 5 6 7 8 9 10 11 12 |
# с помощью функции range создадим последовательность от 1 до 10 с шагом 1 for i in range(1, 11): # если остаток от деления на два не равен нулю (то есть число нечетное) if i % 2 != 0: # идем к следующему числу последовательности continue # в противном случае выводим число else: print(i) |
1 2 3 4 5 |
2 4 6 8 10 |
Как мы видим остались только четные числа.
Форматирование строк в функции print()
Результат работы программы может содержать как текст (строковые значения), так и переменные. Объединить их можно с помощью f-строк (f-string) и метода .format().
Сразу приведем пример.
1 2 3 4 5 6 |
# снова возьмем список с днями недели days = ['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье'] # и для простоты поместим слово "Понедельник" в переменную Monday Monday = days[0] Monday |
1 |
'Понедельник' |
Теперь напишем фразу «Понедельник — день тяжелый» следующим образом.
1 |
print(f'{Monday} - день тяжелый') |
1 |
Понедельник - день тяжелый |
Мы использовали переменную Monday в строке вывода функции print(). Для этого перед строкой мы поставили букву f, а саму переменную заключили в фигурные скобки.
То же самое можно сделать с помощью метода .format().
1 |
print('{} - день тяжелый'.format(Monday)) |
1 |
Понедельник - день тяжелый |
Фигурные скобки внутри строки остались пустыми. К самой строке мы применяем метод .format(), которому передаем нашу переменную.
Мы уже использовали f-строки, когда выводили изображения из датасета MNIST или создавали мешок слов с помощью класса CountVectorizer. Рекомендую вновь посмотреть этот код.
Подведем итог
Систематизируем пройденное на сегодняшнем занятии.
В первой части мы вновь обратились к условиям с if и научились:
- создавать множественные условия с if-elif-else;
- вкладывать одно условие в другое;
- объединять несколько условий с помощью логических операторов and и or; а также
- использовать конструкции if + in и if + not in, чтобы проверить вхождение элемента в список или, например, словарь.
Во второй части мы продолжили изучать цикл for и познакомились с циклом while. Мы узнали, что:
- циклы, как и условия, можно вкладывать один в другой;
- с помощью функций range() мы можем создавать новую последовательность элементов;
- функция enumerate() создает индекс для существующей последовательности;
- цикл while выполняется пока верно определенное условие, а чтобы он не стал бесконечным нужно использовать счетчик.
Кроме того, мы узнали, что циклами можно управлять.
- Оператор break позволяет прервать выполнение цикла;
- Оператор continue прерывает выполнение конкретной итерации, но сам цикл продолжает исполняться.
В заключительной части занятия мы узнали, как можно строковые значения и переменные через f-строки и метод .format().
Вопросы для закрепления
Сколько раз можно вставить оператор elif в конструкцию if-elif-else?
Посмотреть правильный ответ
Ответ: в конструкции if-elif-else (1) оператор elif может быть использован любое количество раз, при этом (2) if и else могут быть использованы только один раз, (3) использование else не обязательно
Обязательно ли использовать f-строку или метод .format() вместе с функцией print()?
Посмотреть правильный ответ
Ответ: нет, не обязательно. При создании мешка слов, мы использовали f-строку для создания индекса датафрейма.
Программирование — это прежде всего практика. Мы прошли довольно много тем и, чтобы закрепить их, в конце ноутбука приведены дополнительные упражнения⧉ . Очень советую выполнить все или хотя бы часть из них.
На следующем занятии мы посмотрим, как работать с файлами в Google Colab.
Ответы на вопросы
Вопрос. В функции range() только один обязательный параметр?
Ответ. Да, совершенно верно. Единственный обязательный параметр — это число, перед которым должна остановиться последовательность. То есть если вы пишете range(7), последовательность начнется с 0 и дойдет до 6 включительно.
Прописав два параметра, вы укажете начало и конец последовательности. Три параметра — начало, конец и шаг.
Вопрос. Можно ли с функцией range() использовать цикл while?
Ответ. Да, можно, но решение, скорее всего, будет не оптимальным. С while такой цикл можно записать следующим образом.
1 2 3 4 |
i = 1 while i in range(1, 11): print('Значение счетчика ', i) i += 1 |
То же самое можно записать в две строчки через for.
1 2 |
for i in range(1, 11): print('Значение счетчика ', i) |
Я добавил этот код в конце ноутбука для наглядности.
Вопрос. Почему range() более эффективна с точки зрения памяти компьютера?
Ответ. Список (list) возвращает набор чисел и сразу размещает все эти числа в оперативной памяти компьютера.
Функция range() возвращает объект range, который представляет собой генератор чисел. Он выдает только одно число за раз и, таким образом, экономит память компьютера.
Вопрос. Почему на занятии по обработке естественного языка в цикле for с функцией enumerate() вы использовали символ нижнего подчеркивания («_»)?
Ответ. Вероятно, вы имеете в виду вот этот код.
Здесь у нас две переменные-контейнера, индекс и предложения. Так как нас интересует только индекс, предложения мы обозначили символом подчеркивания. Другими словами, так обозначают переменные, которые нельзя не указать, но которые затем не используются.
Вопрос. Мне кажется, что в примере с оператором continue без последнего можно обойтись.
Ответ. Да, вы правы, можно обойтись без continue (вариант без этого оператора вы найдете в конце ноутбука). Такой простой пример я конечно привел в учебных целях.
В целом continue удобно использовать для того, чтобы (1) повысить читаемость кода при проверке множества условий (в противном случае вам придется использовать несколько вложенных if) или если вам нужно (2) проверить какое-либо условие перед выполнением очень длинного кода.