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

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

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

In [10]:
x = int(input("Введите число: "))
Введите число: 10
In [11]:
if x < 10:
    print("Мало")
else:
    print("Много")
Много

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

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

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

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

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

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

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

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

In [15]:
if x > 10:
    print("Много")
if x > 6:
    print("Хорошо")
if x > 4:
    print("Неплохо")
else:
    print("Плохо")
Хорошо
Неплохо

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

Случай 1.

In [16]:
mark = int(input("Введите оценку: "))
Введите оценку: 3
In [17]:
if mark < 10:
    print("Это нормально")
elif mark == 10:
    print("Отлично")
if mark < 6:
    print("Плохо")
Это нормально
Плохо

Если оценка меньше 10, мы выводим на экран сообщение "Это нормально", если нет, то проверяем, равна ли она 10: если да, то выводим "Отлично", если нет – ничего не делаем. При этом, после всех этих действий делаем дополнительную проверку: если оценка меньше 6, выводим "Плохо".

Случай 2.

In [18]:
if mark < 10:
    print("Это нормально")
elif mark == 10:
    print("Отлично")
elif mark < 6:
    print("Плохо")
Это нормально

Если оценка меньше 10, мы выводим на экран сообщение "Это нормально", если нет, то проверяем, равна ли она 10: если да, то выводим "Отлично", если нет – сравниваем ее с 6. Если оценка меньше 6, выводим "Плохо".

Почему во втором случае мы не увидели сообщение "Плохо"? Потому что из-за второго elif мы попросту до него не дошли! На ветку со вторым elif мы попадаем в случае, если предыдущее условие не выполняется, то есть если оценка не равна 10. А на ветку с первым elif мы попадем, в случае, если оценка не менее 10. Получается, что мы должны выводить слово "Плохо" в случае, когда оценка более 10 и при этом менее 6, чего в природе не бывает. Использовав elif необдуманно, мы добавили лишнее условие, которое никогда не будет выполняться! Тут будет полезно вспомнить схемы, которые многие, наверное, видели на уроках информатики в школе. Запоминать их необязательно, просто они хорошо иллюстрируют различия между двумя случаями.

Случай 1

title

Случай 2

title

Возможно, предыдущее обсуждение if и elif могло вас чуть-чуть запутать, но это не повод расстраиваться. Важно просто помнить, что разница между этими операторами есть. Остальное можно проверить экспериментально на конкретном примере :)

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

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

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

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

In [20]:
(a < b) and (b > c) # оба верны
Out[20]:
True
In [21]:
(a < b) and (c > b) # второе неверно -> все неверно
Out[21]:
False
In [22]:
(a < b) or (a > c) # первое верное -> хотя бы одно верно
Out[22]:
True
In [23]:
(a < b) or (c > b) # первое верное -> хотя бы одно верно
Out[23]:
True

Можем работать с элементами списков:

In [24]:
L1 = [1, 3, 6, 8]
L2 = [0, 9, 6, 8]
In [25]:
L1[0] > L2[0] # 1 больше 0
Out[25]:
True
In [26]:
(L1[0] > L2[0]) and (L1[2] == L2[2]) # оба верны
Out[26]:
True
In [27]:
(L1[0] > L2[0]) or (L1[2] == L2[2]) # оба верны
Out[27]:
True

Давайте пройдемся по парам элементов в списках L1 и L2, и если значения элементов, которые стоят на одном и том же месте, просто в разных списках, совпадают, мы будем выводить сообщение "It's true! They are equal!", а если нет – сообщение "It's false! They are not equal!".

Сначала посмотрим на длину списков:

In [28]:
print(len(L1))
print(len(L2))
4
4

Списки одинаковой длины, это хорошо! Напишем цикл.

In [29]:
for i in range(0, len(L1)):
    if L1[i] == L2[i]:
        print("It's true! They are equal!")
    else:
        print("It's false! They are not equal!")
It's false! They are not equal!
It's false! They are not equal!
It's true! They are equal!
It's true! They are equal!

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

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

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

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

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

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

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

Цикл while

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

In [33]:
nums = [1, 0, 9, 10, -1, 8]

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

In [34]:
i = 0 # начинаем с индекса i=0

while nums[i] >= 0: # пока элемент nums[i] >= 0
    print(nums[i]) # выводим элемент на экран
    i = i + 1 # переходим к следующему элементу
1
0
9
10

На значении 10 мы остановились: за ним идет значение -1, для которого условие nums[i] > = 0 не выполняется.

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

In [35]:
for n in nums:
    if n >= 0:
        print(n)
    else:
        break # выходим из цикла
1
0
9
10

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

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

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

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

In [38]:
while True:
    guess = int(input("Ваша попытка:"))
    if guess == n:
        print("Вы выиграли!")
        break
    elif guess > n:
        print("Вы ввели слишком большое число.")
    else: 
        print("Вы ввели слишком маленькое число.")
Ваша попытка:53
Вы ввели слишком большое число.
Ваша попытка:32
Вы ввели слишком маленькое число.
Ваша попытка:44
Вы ввели слишком маленькое число.
Ваша попытка:47
Вы ввели слишком маленькое число.
Ваша попытка:52
Вы ввели слишком большое число.
Ваша попытка:51
Вы ввели слишком большое число.
Ваша попытка:49
Вы ввели слишком маленькое число.
Ваша попытка:50
Вы выиграли!

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