{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Основы программирования в Python\n", "\n", "*Алла Тамбовцева, НИУ ВШЭ*\n", "\n", "*Данный ноутбук основан на [лекции](http://nbviewer.math-hse.info/github/ischurov/pythonhse/blob/master/Lecture%203.ipynb#%D0%9F%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D0%B0-%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%B8%D0%B9) Щурова И.В., курс «Программирование на языке Python для сбора и анализа данных» (НИУ ВШЭ).*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Условные конструкции и цикл `while`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Проверка условий" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Начнем с известных всем операторов. Проверим, \n", "\n", "* правда ли, что 8 меньше 9; \n", "* правда ли, что 9 больше 10." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "8 < 9 # правда" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "9 > 10 # неправда" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Результат такой проверки имеет логический тип (*boolean*). " ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "res = 8 < 9\n", "res" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Как мы уже обсуждали, переменные такого типа могут принимать два значения `True` или `False`. Обратите внимание, что `True` и `False` не заключены в кавычки – добавив кавычки, мы получим строки \"True\" и \"False\" (тип *string*)." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"True\" == True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "При проверке равенства двух частей (переменных, списков и так далее) используется двойной знак равенства." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "6 == 6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Одинарный знак «равно» используется для присваивания значений. Так ничего не сравним, но сохраним в переменную `a` число 6:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = 6 \n", "a " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "А так уже проверим условия:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "False\n" ] } ], "source": [ "print(a == 6) \n", "print(a == 9) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Отрицание равенства в Python обозначается с помощью оператора `!=` (вообще `!` в программировании используется для отрицания). " ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "6 != 7" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Стоит отметить, что Python достаточно лояльно относится к разделению между типам данных. Например, если мы сравним целое число и то же число, но с плавающей точкой (с дробной частью равной 0), Python сообщит, что эти числа совпадают." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "6 == 6.0 # верно" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Сложные условия" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Пусть у нас есть три целочисленные переменные `a`, `b` и `c`, и мы планируем составлять сложные, составные уcловия, касающиеся этих переменных." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "a = 3\n", "b = 7\n", "c = 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Помогут операторы `and` и `or`. Оператор `and` соответствует одновременному выполнению условий, оператор `or` соответствует ситуации, когда хотя бы одно из условий выполняется. Оператор `or` в Python – обычное «или», не исключающее: либо верно первое условие, либо второе, либо оба." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(a < b) and (b > c) # оба верны" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(a < b) and (c > b) # второе неверно -> все неверно" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Вместо `and` можно использовать оператор `&`, он нам потом ещё пригодится при работе с датафреймами `pandas`:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(a < b) & (c > b)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(a < b) or (a > c) # первое верное -> хотя бы одно верно" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Вместо `or` можно использовать оператор `|`:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(a < b) | (a > c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Кроме `and` и `or` в Python есть еще полезные операторы: оператор принадлежности `in` и оператор отрицания `not`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Пусть у нас есть списки отличных, хороших, удовлетворительных и плохих оценок." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "excel = [8, 9, 10]\n", "good = [6, 7]\n", "sat = [4, 5]\n", "bad = [1, 2, 3]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Проверим, лежит ли оценка 8 в плохих:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "8 in bad" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Применим отрицание:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "8 not in bad # верно!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Условные конструкции" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Условные конструкции – конструкции с операторами условия. Условная конструкция обычно предполагает «развилку»: если условие выполняется, то должен выполняться один набор действий, если нет – другой набор действий. Давайте напишем программу, которая будет проверять, какое число сохранено в `x`, и если это число менее 10, на экран будет выводиться сообщение \"Мало\", иначе – \"Много\". И заодно познакомимся с конструкцией *if-else*." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "x = 10" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Много\n" ] } ], "source": [ "if x < 10:\n", " print(\"Мало\")\n", "else:\n", " print(\"Много\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "В части с `if` мы прописываем условие, в зависимости от которого Python будет делать выбор, что выводить на экран, а после двоеточия перечисляем действия, которые будут выполняться в случае, если `x` удовлетворяет условию. В части с `else` мы уже не пишем никакого условия – оператор `else` сам по себе означает «в случае, если условие в выражении с `if` не выполнено».\n", "\n", "Часть с `else` является необязательной: программа может существовать только с условием `if`. Тогда в случае невыполнения условия ничего происходить не будет, Python просто перейдет к следующим строкам кода." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "if x < 10:\n", " print(\"Мало\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Как быть, если условий несколько? Например, мы просим пользователя ввести число, и если число больше 10, на экране должно быть сообщение \"Много\", если ровно 10 – \"В самый раз\", если меньше – \"Мало\". Условные конструкции можно вкладывать друг друга, главное не забывать при этом про отступы:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "В самый раз\n" ] } ], "source": [ "if x < 10:\n", " print(\"Мало\")\n", "else:\n", " if x == 10:\n", " print(\"В самый раз\")\n", " else: \n", " print(\"Много\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Можно воспользоваться оператором `elif`, который по смыслу является сочетанием `else + if`: если предыдущее условие невыполнено, то, нужно проверить следующее условие, и если оно тоже не выполнено, то уже перейти к ветке с `else`." ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "В самый раз\n" ] } ], "source": [ "if x < 10:\n", " print(\"Мало\")\n", "elif x == 10:\n", " print(\"В самый раз\")\n", "else: \n", " print(\"Много\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ответвлений с `elif` может быть несколько: сколько условий, столько и выражений с `elif`. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Законный вопрос: а можно ли обойтись совсем без `elif`, просто записав несколько выражений с `if`? Тут все зависит от ситуации. Иногда решения использовать `elif` и `if` будут равнозначными, иногда – нет. \n", "\n", "Рассмотрим такую задачу: в переменной `mark` хранится оценка в 10-балльной шкале, и нам нужно вывести по ней текстовый комментарий (\"Excellent\", \"Good\", \"Satisfactory\" или \"Bad\"). Решим эту задачу с помощью `elif`:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Good\n" ] } ], "source": [ "mark = 6\n", "if mark >= 8:\n", " print(\"Excellent\")\n", "elif mark >= 6:\n", " print(\"Good\")\n", "elif mark >= 4:\n", " print(\"Satisfactory\")\n", "else:\n", " print(\"Bad\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Почему мы можем сделать так? Потому что на каждом шаге, при проверке нового условия мы сужаем круг интересующих нас исходов: если оценка не больше или равна 8, то она точно меньше 8 и сравнивать ее нужно только со следующей «пограничной» оценкой 6, далее, если оценка оказалась меньше 6, остается сравнить ее только с 4 и все. \n", "\n", "В качестве пояснения нарисуем блок-схему для кода выше (скорее всего, сталкивались с такими на уроках информатики):" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![dia.png](dia.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Могли бы решить эту задачу без `elif`, а с помощью сложных условий:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Good\n" ] } ], "source": [ "mark = 6\n", "if mark >= 8:\n", " print(\"Excellent\")\n", "if (mark < 8) and (mark >= 6):\n", " print(\"Good\")\n", "if (mark < 6) and (mark >= 4):\n", " print(\"Satisfactory\")\n", "if (mark < 4):\n", " print(\"Bad\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если бы в конце вместо последнего `if` мы написали конструкцию с `else`, результат был бы другим: " ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Good\n", "Bad\n" ] } ], "source": [ "mark = 6\n", "if mark >= 8:\n", " print(\"Excellent\")\n", "if (mark < 8) and (mark >= 6):\n", " print(\"Good\")\n", "if (mark < 6) and (mark >= 4):\n", " print(\"Satisfactory\")\n", "else:\n", " print(\"Bad\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Почему? Потому что в этом случае часть с `else` относится не ко всем частям с `if` выше, а только к последней, где проверяется принадлежность `mark` промежутку от 6 до 8." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Цикл `while`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "С циклом `for` мы уже знакомы. Сейчас мы познакомимся с циклом `while`, логика которого отличается от `for`. Конструкции с циклом `while` устроены следующим образом: действия, которые указаны в теле цикла, должны выполняться до тех пор, пока верно условие, прописанное после `while` (отсюда и название). Если в цикле `for` мы указывали некоторый промежуток, по которому в ходе цикла мы будем «пробегаться», то в случае с циклом `while` мы просто фиксируем стартовую точку, а конечную точку никак не указываем: программа сама остановится, когда условие в цикле перестанет выполняться." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Давайте, используя цикл `while`, будем выводить на экран элементы списка `turnout` до тех пор, пока не столкнемся со странным значением явки (больше 100)." ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "turnout = [68, 45, 98, 56, 70, 146, 56, 67] " ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "68\n", "45\n", "98\n", "56\n", "70\n" ] } ], "source": [ "i = 0 # начинаем с индекса i=0\n", "\n", "while turnout[i] < 100: # пока элемент nums[i] >= 0\n", " print(turnout[i]) # выводим элемент на экран\n", " i = i + 1 # переходим к следующему элементу" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "На значении 70 мы остановились: за ним идет значение 146, для которого условие `turnout[i] < 100` не выполняется. Python не ожидал такого подвоха и перестал с нами разговаривать :)\n", "\n", "Давайте теперь попробуем переписать код так, чтобы он работал точно так же, но только чтобы в нем использовался цикл `for`, а не `while`. Вообще почти любой код с `while` можно переписать через `for`, и иногда это полезно: код с циклом `while` обычно более медленный, плюс, склонен к зацикливанию." ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "68\n", "45\n", "98\n", "56\n", "70\n" ] } ], "source": [ "for t in turnout:\n", " if t < 100:\n", " print(t)\n", " else:\n", " break # выходим из цикла" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "В коде выше мы использовали оператор `break`, который позволяет выйти из цикла, то есть закончить исполнение строк кода в теле цикла и перейти к коду дальше. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если бы мы хотели модифицировать код таким образом, чтобы он пропускал странное значение, ничего не делал, можно было бы добавить оператор `pass` вместо `break` (отвечает за отсутсвие действия):" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "68\n", "45\n", "98\n", "56\n", "70\n", "56\n", "67\n" ] } ], "source": [ "for t in turnout:\n", " if t < 100:\n", " print(t)\n", " else:\n", " pass" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "А теперь напишем маленькую игру-угадайку. Программа будет загадывать целое число от 1 до 100, а пользователь его угадывать. Как программа будет загадывать число? Выбирать случайным образом из интервала [1, 100] (на самом деле псевдослучайным образом, так как абсолютной случайности не получится, генерирование чисел происходит по фиксированным алгоритмам)." ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "from random import randrange # импортируем модуль для функии randrange" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "n = randrange(1, 101) # n и есть загаданное число" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Осталось написать цикл. До тех пор, пока пользователь не угадает число, программа не будет останавливаться, но зато она будет давать подсказки: если введенное пользователем число больше загаданного, то будет выводиться сообщение \"Вы ввели слишком большое число.\", если меньше – \"Вы ввели слишком маленькое число.\"" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Ваша попытка:68\n", "Вы ввели слишком большое число.\n", "Ваша попытка:56\n", "Вы ввели слишком большое число.\n", "Ваша попытка:25\n", "Вы ввели слишком большое число.\n", "Ваша попытка:15\n", "Вы ввели слишком большое число.\n", "Ваша попытка:7\n", "Вы ввели слишком большое число.\n", "Ваша попытка:1\n", "Вы ввели слишком маленькое число.\n", "Ваша попытка:5\n", "Вы ввели слишком большое число.\n", "Ваша попытка:3\n", "Вы ввели слишком большое число.\n", "Ваша попытка:2\n", "Вы выиграли!\n" ] } ], "source": [ "while True:\n", " guess = int(input(\"Ваша попытка:\"))\n", " if guess == n:\n", " print(\"Вы выиграли!\")\n", " break\n", " elif guess > n:\n", " print(\"Вы ввели слишком большое число.\")\n", " else: \n", " print(\"Вы ввели слишком маленькое число.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "В коде выше в `while` мы не написали никакого условия явно, вместо этого мы написали `while True`. Это выражение означает «до тех пор, пока мы не вышли из цикла». В нашем случае это равносильно «до тех пор, пока не столкнулись с `break`», пока наш ответ не совпал с загаданным числом. Неформально можно считать, что конструкция `while True` – своеобразная альтернатива «бесконечному» циклу `for`." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.8" } }, "nbformat": 4, "nbformat_minor": 2 }