Условия и циклы. Продолжение | Программирование на Питоне

Условия и циклы. Продолжение

Все курсы > Программирование на Питоне > Занятие 3

На шестом занятии вводного курса ML мы уже начали изучать условия и циклы. Продолжим этот путь.

Вначале откроем ноутбук к этому занятию

Еще раз про условия с if

Помимо базовой уже известной нам структуры if-else, мы также можем прописать несколько условий (multi-way decisions) с помощью if-elif-else. Слово elif в данном случае как раз и позволяет добавить новые условия.

Например, мы хотим написать программу, которая разделит все передаваемые ей числа на малые (small), средние (medium) и большие (large). Сначала посмотрим на блок-схему.

множественные условия с if-elif-else

Если слово меньше 10, то оно малое, меньше 100 — среднее, в противном случае оно большое. Теперь пропишем это на Питоне.

До сих пор мы записывали число или строку в переменную. Пора познакомиться с возможностью ввода числа с клавиатуры. В этом нам поможет встроенная в Питон функция input(). В частности, описанная выше программа могла бы запрашивать число у пользователя, а уже потом классифицировать.

При исполнении этого кода вначале появляется поле для ввода.

результат функции input() в Google Colab

После ввода числа и нажатия клавиши Enter, мы получаем результат.

Обратите внимание на два момента. Во-первых, внутри функции input() в кавычках мы пишем сообщение, которое увидит пользователь. Во-вторых, любые введенные нами символы воспринимаются как тип str (string, строка). Соответственно, если мы хотим, чтобы ввод считался числом, сначала нужно его преобразовать с помощью функции int().

Помимо этого, одно условие может быть вложено в другое (nested decisions). Приведем пример.

Если ввести число, то алгоритм продолжит классификацию.

В противном случае, оставив ввод пустым и нажав Enter, классификация будет опущена и мы получим следующее сообщение.

В коде можно прописать сразу несколько условий в одном выражении. Например, можно объединить if c логическими операторами and или or. Вначале приведу пример с логическим И.

А также логическим ИЛИ.

С помощью if мы можем проверить, входит ли элемент в состав какого-либо объекта или нет. Для этого используются операторы in и not in.

  • Оператор in возвращает True, если элемент входит в объект
  • Оператор not in возвращает True, если элемент не входит в объект

Посмотрим на примерах.

Еще раз обращу ваше внимание на то, что not in возвращает True, когда элемента НЕТ в объекте. Именно поэтому в примере со списком условие после if выполнилось.

Применим оператор in к словарю.

Теперь давайте поговорим про циклы.

Циклы

циклы for и while в Питоне

Цикл for

С циклом for (for loop) мы уже знакомы. Повторим пройденное на несложном примере.

Мы также умеем выводить элементы словаря.

Помимо этого мы можем вывести только ключи или только значения с помощью методов .keys() и .values() соответственно.

Предположим, что мы хотим вывести только числа (первый элемент значения словаря).

Цикл for можно применить к массиву Numpy.

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

База данных представляет собой словарь. Ключами являются id клиентов. Значениями — еще один (вложенный) словарь с информацией о каждом клиенте.

Ключами второго (вложенного) словаря выступают названия полей (ФИО, возраст, пол и выручка с клиента), а значениями — соответствующая информация. Выведем все эти данные.

Два комментария.

  • Обратите особое внимание на отступы слева, они указывают на очередность выполнения операций. Например, пустая команда print() (и соответственно пустая строка) имеет один отступ, чтобы исполниться после каждого клиента, а не после каждого поля с информацией о клиенте.
  • При использовании функции print() мы можем объединить несколько строк, а вот объединить строку и число нельзя. Так как id, значение возраста (age) и значение выручки (revenue) являются числами (тип int), их нужно сначала принудительно сделать строкой через функцию str().

Функции range() и enumerate()

Иногда нам нужно создать последовательность чисел и пройтись по ней в цикле. Конечно, можно создать список и заполнить его нужными элементами, но, во-первых, для этого надо написать много кода, во-вторых, это будет неэффективно с точки зрения памяти компьютера. Для этого есть специальная функция range().

Приведем несколько примеров.

Теперь рассмотрим, как мы получили такие результаты более детально.

параметры функции range(start, stop, step)
подробное описание параметров функции range()

Функция 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(), то такую конструкцию можно использовать для того, чтобы в одном цикле вывести все элементы, например, двух списков по их индексу.

Мы уже применяли эту функцию. На занятии по кластеризации, в методе k-средних мы пробовали разное количество кластеров и смотрели как изменится ошибка модели. Эта функция также использовалась нами при создании рекомендательной системы и в модели экспоненциального сглаживания.

Еще раз посмотрите код прошлых уроков, это будет полезным упражнением.

В целом, если вы хотите найти какой-либо код на этом сайте, воспользуйтесь поиском по сайту (иконка лупы).

Теперь давайте посмотрим на функцию enumerate(). Мы можем использовать эту функцию, если у нас есть, например, список и, проходясь в цикле по этому списку, мы хотим также получить порядковый номер (индекс) элементов списка.

Все бы хорошо, но неделю логичнее начинать с первого дня, а не с нулевого. Для этого функции enumerate() можно передать начальное значение.

Эту функцию мы уже применяли на занятии по компьютерному зрению и обработке естественного языка.

Цикл while

С циклом while (while loop) мы пока не знакомы. Как уже было сказано, цикл выполняется пока верно прописанное в нем условие.

синтаксис цикла while

В целом все просто, но есть один нюанс.

Условие должно в какой-то момент перестать быть верным, иначе цикл станет бесконечным. Для этого существует счетчик (counter).

Посмотрим как это можно реализовать на Питоне.

Рассмотрим еще раз, как мы получили такой результат.

  • У нас есть начальное значение счетчика, равное нулю (i = 0) (хотя конечно значение счетчика может быть любым)
  • При первой итерации, так как 0 < 3, исполняем код в цикле и увеличиваем счетчик на 1 (теперь i = 1)
  • На второй итерации, 1 < 3, условие по-прежнему верно, снова исполняем код и увеличиваем счетчик на 1 (i = 2)
  • На третьей итерации, 2 < 3, условие верно, исполняем код и увеличиваем счетчик на 1 (i = 3)
  • Далее, алгоритм пытается выполнить четвертую итерацию цикла, однако так как 3 < 3 неверно, цикл прерывается

Небольшой лайфхак. Вместо того, чтобы писать i = i + 1 Питон позволяет использовать короткую запись: i += 1.

Оператор += увеличивает значение переменной и одновременно присваивает ей это новое увеличенное значение. Короткая запись также применяется к операциям вычитания ( -=), умножения ( *=) и деления ( /=).

Операторы break и continue

Ходом исполнения цикла можно управлять.

Оператор break

Представьте, что вы пишете цикл, который затем примените к очень длинному словарю или списку (в нем, например, 10 тыс. элементов), но вы не уверены в своем коде. Если цикл применить сразу ко всему объекту и при этом окажется, что код делает не совсем то, что вы хотите, то придется ждать, пока компьютер выведет все 10 тыс. записей.

Логично протестировать код на первой записи, а уже потом двигаться дальше. В этом нам поможет оператор break (прерывание цикла).

Цикл можно также прерывать при наступлении определенного условия.

Мы прервали цикл, когда значение счетчика стало равно трем.

Также обратите внимание, что здесь цикл двигается в сторону уменьшения (с помощью -=). Мы начали с x = 6 и должны были вывести значения 6, 5, 4, 3, 2, 1, если бы условие не прервало выполнение цикла.

Оператор continue

Иногда цикл не нужно прерывать, но нужно как бы «перескочить» одну или несколько итераций этого цикла. В этом случае применяется оператор continue.

Предположим, нам нужно создать последовательность целых чисел от 1 до 10 включительно и вывести только четные числа.

Как мы помним, четное число — это число, которое делится на два без остатка.

Последовательность создавать мы умеем. Взятие остатка от деления мы уже рассмотрели на прошлом занятии. Осталось написать код целиком.

Как мы видим остались только четные числа.

Форматирование строк в функции print()

Результат работы программы может содержать как текст (строковые значения), так и переменные. Объединить их можно с помощью f-строк (f-string) и метода .format().

Сразу приведем пример.

Теперь напишем фразу «Понедельник — день тяжелый» следующим образом.

Мы использовали переменную Monday в строке вывода функции print(). Для этого перед строкой мы поставили букву f, а саму переменную заключили в фигурные скобки.

То же самое можно сделать с помощью метода .format().

Фигурные скобки внутри строки остались пустыми. К самой строке мы применяем метод .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 такой цикл можно записать следующим образом.

То же самое можно записать в две строчки через for.

Я добавил этот код в конце ноутбука для наглядности.


Вопрос. Почему range() более эффективна с точки зрения памяти компьютера?

Ответ. Список (list) возвращает набор чисел и сразу размещает все эти числа в оперативной памяти компьютера.

Функция range() возвращает объект range, который представляет собой генератор чисел. Он выдает только одно число за раз и, таким образом, экономит память компьютера.


Вопрос. Почему на занятии по обработке естественного языка в цикле for с функцией enumerate() вы использовали символ нижнего подчеркивания («_»)?

Ответ. Вероятно, вы имеете в виду вот этот код.

Здесь у нас две переменные-контейнера, индекс и предложения. Так как нас интересует только индекс, предложения мы обозначили символом подчеркивания. Другими словами, так обозначают переменные, которые нельзя не указать, но которые затем не используются.


Вопрос. Мне кажется, что в примере с оператором continue без последнего можно обойтись.

Ответ. Да, вы правы, можно обойтись без continue (вариант без этого оператора вы найдете в конце ноутбука). Такой простой пример я конечно привел в учебных целях.

В целом continue удобно использовать для того, чтобы (1) повысить читаемость кода при проверке множества условий (в противном случае вам придется использовать несколько вложенных if) или если вам нужно (2) проверить какое-либо условие перед выполнением очень длинного кода.