Основы программирования в Python

Алла Тамбовцева, НИУ ВШЭ

Данный ноутбук основан на лекции Щурова И.В., курс «Программирование на языке Python для сбора и анализа данных» (НИУ ВШЭ).

Условные конструкции и цикл while

Проверка условий

Начнем с известных всем операторов. Проверим,

  • правда ли, что 8 меньше 9;
  • правда ли, что 9 больше 10.
In [1]:
8 < 9 # правда
Out[1]:
True
In [2]:
9 > 10 # неправда
Out[2]:
False

Результат такой проверки имеет логический тип (boolean).

In [3]:
res = 8 < 9
res
Out[3]:
True

Как мы уже обсуждали, переменные такого типа могут принимать два значения True или False. Обратите внимание, что True и False не заключены в кавычки – добавив кавычки, мы получим строки "True" и "False" (тип string).

In [4]:
"True" == True
Out[4]:
False

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

In [5]:
6 == 6
Out[5]:
True

Одинарный знак «равно» используется для присваивания значений. Так ничего не сравним, но сохраним в переменную a число 6:

In [6]:
a = 6 
a 
Out[6]:
6

А так уже проверим условия:

In [7]:
print(a == 6) 
print(a == 9) 
True
False

Отрицание равенства в Python обозначается с помощью оператора != (вообще ! в программировании используется для отрицания).

In [8]:
6 != 7
Out[8]:
True

Стоит отметить, что Python достаточно лояльно относится к разделению между типам данных. Например, если мы сравним целое число и то же число, но с плавающей точкой (с дробной частью равной 0), Python сообщит, что эти числа совпадают.

In [9]:
6 == 6.0 # верно
Out[9]:
True

Сложные условия

Пусть у нас есть три целочисленные переменные a, b и c, и мы планируем составлять сложные, составные уcловия, касающиеся этих переменных.

In [10]:
a = 3
b = 7
c = 1

Помогут операторы and и or. Оператор and соответствует одновременному выполнению условий, оператор or соответствует ситуации, когда хотя бы одно из условий выполняется. Оператор or в Python – обычное «или», не исключающее: либо верно первое условие, либо второе, либо оба.

In [11]:
(a < b) and (b > c) # оба верны
Out[11]:
True
In [12]:
(a < b) and (c > b) # второе неверно -> все неверно
Out[12]:
False

Вместо and можно использовать оператор &, он нам потом ещё пригодится при работе с датафреймами pandas:

In [13]:
(a < b) & (c > b)
Out[13]:
False
In [14]:
(a < b) or (a > c) # первое верное -> хотя бы одно верно
Out[14]:
True

Вместо or можно использовать оператор |:

In [15]:
(a < b) | (a > c)
Out[15]:
True

Кроме and и or в Python есть еще полезные операторы: оператор принадлежности in и оператор отрицания not.

Пусть у нас есть списки отличных, хороших, удовлетворительных и плохих оценок.

In [16]:
excel = [8, 9, 10]
good = [6, 7]
sat = [4, 5]
bad = [1, 2, 3]

Проверим, лежит ли оценка 8 в плохих:

In [17]:
8 in bad
Out[17]:
False

Применим отрицание:

In [18]:
8 not in bad # верно!
Out[18]:
True

Условные конструкции

Условные конструкции – конструкции с операторами условия. Условная конструкция обычно предполагает «развилку»: если условие выполняется, то должен выполняться один набор действий, если нет – другой набор действий. Давайте напишем программу, которая будет проверять, какое число сохранено в x, и если это число менее 10, на экран будет выводиться сообщение "Мало", иначе – "Много". И заодно познакомимся с конструкцией if-else.

In [19]:
x = 10
In [20]:
if x < 10:
    print("Мало")
else:
    print("Много")
Много

В части с if мы прописываем условие, в зависимости от которого Python будет делать выбор, что выводить на экран, а после двоеточия перечисляем действия, которые будут выполняться в случае, если x удовлетворяет условию. В части с else мы уже не пишем никакого условия – оператор else сам по себе означает «в случае, если условие в выражении с if не выполнено».

Часть с else является необязательной: программа может существовать только с условием if. Тогда в случае невыполнения условия ничего происходить не будет, Python просто перейдет к следующим строкам кода.

In [21]:
if x < 10:
    print("Мало")

Как быть, если условий несколько? Например, мы просим пользователя ввести число, и если число больше 10, на экране должно быть сообщение "Много", если ровно 10 – "В самый раз", если меньше – "Мало". Условные конструкции можно вкладывать друг друга, главное не забывать при этом про отступы:

In [22]:
if x < 10:
    print("Мало")
else:
    if x == 10:
        print("В самый раз")
    else: 
        print("Много")
В самый раз

Можно воспользоваться оператором elif, который по смыслу является сочетанием else + if: если предыдущее условие невыполнено, то, нужно проверить следующее условие, и если оно тоже не выполнено, то уже перейти к ветке с else.

In [23]:
if x < 10:
    print("Мало")
elif x == 10:
    print("В самый раз")
else: 
    print("Много")
В самый раз

Ответвлений с elif может быть несколько: сколько условий, столько и выражений с elif.

Законный вопрос: а можно ли обойтись совсем без elif, просто записав несколько выражений с if? Тут все зависит от ситуации. Иногда решения использовать elif и if будут равнозначными, иногда – нет.

Рассмотрим такую задачу: в переменной mark хранится оценка в 10-балльной шкале, и нам нужно вывести по ней текстовый комментарий ("Excellent", "Good", "Satisfactory" или "Bad"). Решим эту задачу с помощью elif:

In [24]:
mark = 6
if mark >= 8:
    print("Excellent")
elif mark >= 6:
    print("Good")
elif mark >= 4:
    print("Satisfactory")
else:
    print("Bad")
Good

Почему мы можем сделать так? Потому что на каждом шаге, при проверке нового условия мы сужаем круг интересующих нас исходов: если оценка не больше или равна 8, то она точно меньше 8 и сравнивать ее нужно только со следующей «пограничной» оценкой 6, далее, если оценка оказалась меньше 6, остается сравнить ее только с 4 и все.

В качестве пояснения нарисуем блок-схему для кода выше (скорее всего, сталкивались с такими на уроках информатики):

dia.png

Могли бы решить эту задачу без elif, а с помощью сложных условий:

In [25]:
mark = 6
if mark >= 8:
    print("Excellent")
if (mark < 8) and (mark >= 6):
    print("Good")
if (mark < 6) and (mark >= 4):
    print("Satisfactory")
if (mark < 4):
    print("Bad")
Good

Если бы в конце вместо последнего if мы написали конструкцию с else, результат был бы другим:

In [26]:
mark = 6
if mark >= 8:
    print("Excellent")
if (mark < 8) and (mark >= 6):
    print("Good")
if (mark < 6) and (mark >= 4):
    print("Satisfactory")
else:
    print("Bad")
Good
Bad

Почему? Потому что в этом случае часть с else относится не ко всем частям с if выше, а только к последней, где проверяется принадлежность mark промежутку от 6 до 8.

Цикл while

С циклом for мы уже знакомы. Сейчас мы познакомимся с циклом while, логика которого отличается от for. Конструкции с циклом while устроены следующим образом: действия, которые указаны в теле цикла, должны выполняться до тех пор, пока верно условие, прописанное после while (отсюда и название). Если в цикле for мы указывали некоторый промежуток, по которому в ходе цикла мы будем «пробегаться», то в случае с циклом while мы просто фиксируем стартовую точку, а конечную точку никак не указываем: программа сама остановится, когда условие в цикле перестанет выполняться.

Давайте, используя цикл while, будем выводить на экран элементы списка turnout до тех пор, пока не столкнемся со странным значением явки (больше 100).

In [27]:
turnout = [68, 45, 98, 56, 70, 146, 56, 67] 
In [28]:
i = 0 # начинаем с индекса i=0

while turnout[i] < 100: # пока элемент nums[i] >= 0
    print(turnout[i]) # выводим элемент на экран
    i = i + 1 # переходим к следующему элементу
68
45
98
56
70

На значении 70 мы остановились: за ним идет значение 146, для которого условие turnout[i] < 100 не выполняется. Python не ожидал такого подвоха и перестал с нами разговаривать :)

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

In [29]:
for t in turnout:
    if t < 100:
        print(t)
    else:
        break # выходим из цикла
68
45
98
56
70

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

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

In [30]:
for t in turnout:
    if t < 100:
        print(t)
    else:
        pass
68
45
98
56
70
56
67

А теперь напишем маленькую игру-угадайку. Программа будет загадывать целое число от 1 до 100, а пользователь его угадывать. Как программа будет загадывать число? Выбирать случайным образом из интервала [1, 100] (на самом деле псевдослучайным образом, так как абсолютной случайности не получится, генерирование чисел происходит по фиксированным алгоритмам).

In [31]:
from random import randrange # импортируем модуль для функии randrange
In [32]:
n = randrange(1, 101) # n и есть загаданное число

Осталось написать цикл. До тех пор, пока пользователь не угадает число, программа не будет останавливаться, но зато она будет давать подсказки: если введенное пользователем число больше загаданного, то будет выводиться сообщение "Вы ввели слишком большое число.", если меньше – "Вы ввели слишком маленькое число."

In [33]:
while True:
    guess = int(input("Ваша попытка:"))
    if guess == n:
        print("Вы выиграли!")
        break
    elif guess > n:
        print("Вы ввели слишком большое число.")
    else: 
        print("Вы ввели слишком маленькое число.")
Ваша попытка:68
Вы ввели слишком большое число.
Ваша попытка:56
Вы ввели слишком большое число.
Ваша попытка:25
Вы ввели слишком большое число.
Ваша попытка:15
Вы ввели слишком большое число.
Ваша попытка:7
Вы ввели слишком большое число.
Ваша попытка:1
Вы ввели слишком маленькое число.
Ваша попытка:5
Вы ввели слишком большое число.
Ваша попытка:3
Вы ввели слишком большое число.
Ваша попытка:2
Вы выиграли!

В коде выше в while мы не написали никакого условия явно, вместо этого мы написали while True. Это выражение означает «до тех пор, пока мы не вышли из цикла». В нашем случае это равносильно «до тех пор, пока не столкнулись с break», пока наш ответ не совпал с загаданным числом. Неформально можно считать, что конструкция while True – своеобразная альтернатива «бесконечному» циклу for.