while
¶Начнем с известных всем операторов. Проверим,
8 < 9 # правда
True
9 > 10 # неправда
False
Результат такой проверки имеет логический тип (boolean).
res = 8 < 9
res
True
Как мы уже обсуждали, переменные такого типа могут принимать два значения True или False. Обратите внимание, что True и False не заключены в кавычки ‒ добавив кавычки, мы получим строки "True" и "False".
"True" == True
False
При проверке равенства двух частей (переменных, списков и так далее) используется двойной знак "равно".
6 == 6
True
Одинарный знак "равно" используется для присваивания значений. Так ничего не сравним, но сохраним в переменную a
число 6:
a = 6
a
6
А так уже проверим условия:
print(a == 6)
print(a == 9)
True False
Неравенство, то есть отрицание равенства, в Python обозначается с помощью оператора !=
(вообще !
в программировании используется для отрицания).
6 != 7
True
Стоит отметить, что Python достаточно лояльно относится к разделению между типам данных. Например, если мы сравним целое число и то же число, но с плавающей точкой (с дробной частью равной 0), Python сообщит, что эти числа совпадают.
6 == 6.0 # верно
True
Условные конструкции ‒ конструкции с операторами условия. Условная конструкция обычно предполагает "развилку": если условие выполняется, то должен выполняться один набор действий, если нет ‒ другой набор действий. Давайте напишем программу, которая будет просить пользователя ввести целое число, и если это число менее 10, на экран будет выводиться сообщение "Мало", иначе ‒ "Много". И заодно познакомимся с конструкцией if-else.
x = int(input("Введите число: "))
Введите число: 10
if x < 10:
print("Мало")
else:
print("Много")
Много
В части с if
мы прописываем условие, в зависимости от которого Python будет делать выбор, что выводить на экран, а после двоеточия перечисляем действия, которые будут выполняться в случае, если x
удовлетворяет условию. В части с else
мы уже не пишем никакого условия ‒ оператор else
сам по себе означает "в случае, если условие в выражении с if
не выполнено".
Часть с else
является необязательной: программа может существовать только с условием if
. Тогда в случае невыполнения условия ничего происходить не будет, Python просто перейдет к следующим строкам кода.
Как быть, если условий несколько? Например, мы просим пользователя ввести оценку, и если оценка больше 10, на экране должно быть сообщение "Много", если ровно 10 ‒ "В самый раз", если меньше ‒ "Мало". Можно воспользоваться оператором elif
, который по смыслу является сочетанием else + if
: если предыдущее условие невыполнено, то, нужно проверить следующее условие, и если оно тоже не выполнено, то уже перейти к ветке с else
.
mark = int(input("Введите оценку: "))
Введите оценку: 3
if mark > 10:
print("Много")
elif mark == 10:
print("В самый раз")
else:
print("Мало")
Мало
Ответвлений с elif
может быть несколько: сколько условий, столько и выражений с elif
. Добавим еще одно условие:
if mark > 10:
print("Много")
elif mark > 6:
print("Хорошо")
elif mark > 4:
print("Неплохо")
else:
print("Плохо")
Плохо
Законный вопрос: а можно ли обойтись совсем без elif
, просто записав несколько выражений с if
? Тут все зависит от ситуации. Иногда решения использовать elif
и if
будут равнозначными. Если мы перепишем код в примере выше, заменив elif
на if
, ничего не изменится, так как условия будут проверяться последовательно в любом случае: если оценка больше 10, будет выведено слово "Много", если нет ‒ программа перейдет к следующему условию, и так далее.
if mark > 10:
print("Много")
if mark > 6:
print("Хорошо")
if mark > 4:
print("Неплохо")
else:
print("Плохо")
Плохо
В случае, когда условия как-то связаны между собой, нужно быть более внимательными. Рассмотрим такой пример.
Случай 1.
if mark < 10:
print("Это нормально")
elif mark == 10:
print("Отлично")
if mark < 6:
print("Плохо")
Это нормально Плохо
Если оценка меньше 10, мы выводим на экран сообщение "Это нормально", если нет, то проверяем, равна ли она 10: если да, то выводим "Отлично", если нет ‒ ничего не делаем. При этом, после всех этих действий делаем дополнительную проверку: если оценка меньше 6, выводим "Плохо".
Случай 2.
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
Случай 2
Возможно, предыдущее обсуждение if
и elif
могло вас чуть-чуть запутать, но это не повод расстраиваться. Важно просто помнить, что разница между этими операторами есть. Остальное можно проверить экспериментально на конкретном примере :)
Пусть у нас есть три целочисленные переменные a
, b
и c
, и мы планируем составлять сложные, составные уcловия, касающиеся этих переменных.
a = 3
b = 7
c = 1
Помогут операторы and
и or
. Оператор and
соответствует одновременному выполнению условий, оператор or
соответствует ситуации, когда хотя бы одно из условий выполняется. Оператор or
в Python ‒ обычное "или", не исключающее: либо верно первое условие, либо второе, либо оба.
(a < b) and (b > c) # оба верны
True
(a < b) and (c > b) # второе неверно -> все неверно
False
(a < b) or (a > c) # первое верное -> хотя бы одно верно
True
(a < b) or (c > b) # первое верное -> хотя бы одно верно
True
Можем работать с элементами списков:
l1 = [1, 3, 6, 8]
l2 = [0, 9, 6, 8]
l1[0] > l2[0] # 1 больше 0
True
(l1[0] > l2[0]) and (l1[2] == l2[2]) # оба верны
True
(l1[0] > l2[0]) or (l1[2] == l2[2]) # оба верны
True
Давайте пройдемся по парам элементов в списках l1
и l2
, и если значения элементов, которые стоят на одном и том же месте, просто в разных списках, совпадают, мы будем выводить сообщение "It's true! They are equal!", а если нет ‒ сообщение "It's false! They are not equal!".
Сначала посмотрим на длину списков:
print(len(l1))
print(len(l2))
4 4
Списки одинаковой длины, это хорошо! Напишем цикл.
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!
А теперь предлагаю вам такую задачу. Есть список оценок marks
, и для каждой оценки нужно вывести комментарий (Отлично, Хорошо, Удовлетворительно, Плохо) с новой строки.
marks = [2, 7, 8, 10, 5, 8, 1, 6]
Решение:
for mark in marks:
if mark >= 8:
print("Отлично!")
elif (mark >= 6) and (mark < 8):
print("Хорошо!")
elif (mark >= 4) and (mark < 6):
print("Удовлетворительно!")
else:
print("Плохо!")
Плохо! Хорошо! Отлично! Отлично! Удовлетворительно! Отлично! Плохо! Хорошо!
Можно написать аналогичный код, но оценку теперь будет вводить пользователь с клавиатуры.
mark = int(input("Введите оценку: "))
if mark >= 8:
print("Отлично!")
elif (mark >= 6) and (mark < 8):
print("Хорошо!")
elif (mark >= 4) and (mark < 6):
print("Удовлетворительно!")
else:
print("Плохо!")
Введите оценку: 6 Хорошо!
Небольшое лирическое отступление, не связанное с условиями. В Python есть функция eval()
, которая позволяет исполнять код, который записан в виде строки. Например, мы сохранили в текстовый файл какие-то списки. Открываем файл, и Python считывает наши списки как обычные строки:
s = "[2,5,6,8]"
s
'[2,5,6,8]'
Если мы применим к строке s
функцию eval()
, мы получим список.
L = eval(s)
L
[2, 5, 6, 8]
Работает это не только для списков:
eval("a == 8")
False
Внимание: использование функции eval()
считается небезопасным в том смысле, что она исполняет любой код, заключенный в строке, не проверяя при этом, является ли код хорошим, правильным. Более корректно было бы использовать функцию literal_eval()
, которую вы можете встретить в автоматических тестах в домашних заданиях. Эту функцию нужно импортировать из модуляast
:
from ast import literal_eval
literal_eval("[1,2,3]")
[1, 2, 3]
Кроме and
и or
в Python есть еще полезные операторы: оператор принадлежности in
и оператор отрицания not
.
Пусть у нас есть списки отличных, хороших, удовлетворительных и плохих оценок.
excel = [8, 9, 10]
good = [6, 7]
sat = [4, 5]
bad = [1, 2, 3]
Проверим, лежит ли оценка 8 в плохих:
8 in bad
False
Применим отрицание:
8 not in bad # верно!
True
Иногда возникает необходимость проверять разные отношения между двумя наборами элементов. Например, проверить, есть ли у двух списков общие элементы. Для этого можно воспользоваться уже известным оператором in
:
L1 = [1, 3, 4]
L2 = [1, 4, 5, 6]
for i in L2:
if i in L1:
print(i)
1 4
Но иногда удобно превратить списки в множества (sets) и выполнять операции, которые определены для множеств в математике: пересечение, объединение, разность и так далее.
Важно иметь в виду, что в множествах (как в программировании, так и в математике) не может быть повторяющихся элементов. Поэтому, если в списке есть повторяющиеся значения, и они важны, превращать спискок в множество не стоит, так как можно потерять элементы.
numbers = [1, 1, 0, 2, 4, 3, 3] # 7 элементов
set(numbers) # в множестве осталось 5 элементов + отсортированы по возрастанию
{0, 1, 2, 3, 4}
Множества из строк тоже существуют (вообще их можно создавать из любых объектов):
words = ["one", "one", "two", "three"] # пока список
set(words) # множество
{'one', 'three', 'two'}
А теперь превратим два числовых списка в множества A и B и попробуем произвести некоторые операции.
A = set([0, 2, 4, 7])
B = set([0, 1, 4, 5])
Пересечение множеств A и B ‒ общие элементы этих двух множеств:
B.intersection(A) # метод intersection
{0, 4}
Объединение множеств A и B ‒ все элементы множества A и множества B (но, конечно, без повторений):
A.union(B) # метод union
{0, 1, 2, 4, 5, 7}
Разность множеств B и A ‒ все элементы множества B, которых нет в A.
B.difference(A) # метод difference
{1, 5}
Обратите внимание: результат, полученный после использования методов для множеств, тоже является множеством ‒ элементы перечислены в фигурных скобках. Но при желании результат можно превратить в список:
list(A.difference(B))
[2, 7]
Множество в Python, наверное, не такой распространенный объект как список, кортеж или словарь (о них поговорим позже), но знать о них полезно, потому что в некоторых задачах использовать методы для множеств гораздо эффективнее, чем писать какие-то циклы с разными условиями.
while
¶С циклом for
мы уже знакомы. Сейчас мы познакомимся с циклом while
, логика которого отличается от for
. Конструкции с циклом while
устроены следующим образом: действия, которые указаны в теле цикла, должны выполняться до тех пор, пока верно условие, прописанное после while
(отсюда и название). Если в цикле for
мы указывали некоторый промежуток, по которому в ходе цикла мы будем "пробегаться", то в случае с циклом while
мы просто фиксируем стартовую точку, а конечную точку никак не указываем: программа сама остановится, когда условие в цикле перестанет выполняться.
nums = [1, 0, 9, 10, -1, 8]
Давайте, используя цикл while
, будем выводить на экран элементы списка nums
до тех пор, пока не столкнемся с отрицательным значением.
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
обычно более медленный, плюс, склонен к зацикливанию.
for n in nums:
if n >= 0:
print(n)
else:
break # выходим из цикла
1 0 9 10
В коде выше мы использовали оператор break
, который позволяет выйти из цикла, то есть закончить исполнение строк кода в теле цикла и перейти к коду дальше.
А теперь напишем маленькую игру-угадайку. Программа будет загадывать целое число от 1 до 100, а пользователь его угадывать. Как программа будет загадывать число? Выбирать случайным образом из интервала [1, 100] (на самом деле псевдослучайным образом, так как абсолютной случайности не получится, генерирование чисел происходит по фиксированным алгоритмам).
from random import randrange # импортируем модуль для функии randrange
n = randrange(1, 101) # n и есть загаданное число
Осталось написать цикл. До тех пор, пока пользователь не угадает число, программа не будет останавливаться, но зато она будет давать подсказки: если введенное пользователем число больше загаданного, то будет выводиться сообщение "Вы ввели слишком большое число.", если меньше ‒ "Вы ввели слишком маленькое число."
while True:
guess = int(input("Ваша попытка:"))
if guess == n:
print("Вы выиграли!")
break
elif guess > n:
print("Вы ввели слишком большое число.")
else:
print("Вы ввели слишком маленькое число.")
Ваша попытка:23 Вы ввели слишком большое число. Ваша попытка:11 Вы ввели слишком маленькое число. Ваша попытка:15 Вы ввели слишком маленькое число. Ваша попытка:20 Вы ввели слишком большое число. Ваша попытка:18 Вы ввели слишком большое число. Ваша попытка:17 Вы ввели слишком большое число. Ваша попытка:16 Вы выиграли!
В коде выше в while
мы не написали никакого условия явно, вместо этого мы написали while True
. Это выражение означает "до тех пор, пока мы не вышли из цикла". В нашем случае это равносильно "до тех пор, пока не столкнулись с break
, пока наш ответ не совпал с загаданным числом.