Программирование с нуля Условия: как программа принимает решения
0%

Условия: как программа принимает решения

Условия: как программа принимает решения

До сих пор наши программы были похожи на список поручений: сделай раз, сделай два, сделай три — и всегда одинаково. Такая программа полезна, но она не умеет главного: реагировать. Настоящие программы всё время что-то решают. Пароль подошёл или нет? Товара хватает на складе или нет? Пользователь совершеннолетний или нет? От ответа зависит, что произойдёт дальше.

Механизм, который отвечает за такие развилки, называется условием (по-английски conditional). В Python он записывается словами if, elif и else. Это, пожалуй, первая по-настоящему «умная» конструкция, которую вы изучите — и одна из тех, которыми вы будете пользоваться каждый день до конца карьеры.

Мы будем опираться на переменные и типы данных из статьи Переменные и типы данных. Если что-то из неё забылось — ничего страшного, я буду напоминать по ходу.

Аналогия: развилка на дороге

Представьте, что вы идёте по тропинке и доходите до развилки. Рядом стоит табличка: «Если идёт дождь — сворачивай направо, к навесу. Иначе — иди прямо, через поле». Вы смотрите на небо, отвечаете себе «да» или «нет» и идёте по одной из двух троп. Потом обе тропы снова сходятся, и вы продолжаете путь.

Условие в программе устроено ровно так же:

  • есть вопрос, на который можно ответить только «да» или «нет» (идёт ли дождь);
  • есть ветка на случай «да»;
  • есть (не обязательно) ветка на случай «нет»;
  • после развилки программа продолжает работу как ни в чём не бывало.

Где аналогия ломается. На реальной развилке вы можете постоять, подумать, вернуться назад. Программа так не умеет: она проверяет условие ровно один раз, мгновенно выбирает ветку и идёт дальше. Вернуться и «переиграть» решение она не может — если только вы сами не напишете такую логику. Ещё важно: программа не понимает «наверное» или «почти». Ответ строго один из двух.

«Да» и «нет» на языке программы: тип bool

Чтобы задать вопрос, нужен способ записать ответ. В Python для этого есть отдельный тип данных — bool (читается «бул», от фамилии математика Джорджа Буля). У него всего два возможных значения:

  • True — истина, «да»;
  • False — ложь, «нет».

Пишутся они с большой буквы и без кавычек. true (с маленькой) Python не поймёт, а "True" в кавычках — это уже обычный текст, а не истина.

is_raining = True      # переменная хранит "да"
is_sunny = False       # переменная хранит "нет"

print(is_raining)      # выведет: True
print(type(is_sunny))  # выведет: <class 'bool'>

Ожидаемый вывод:

True
<class 'bool'>

type(...) — это встроенная команда, которая сообщает тип значения. <class 'bool'> означает «это булево значение».

Откуда берутся True и False: операторы сравнения

Вручную писать True приходится редко. Обычно ответ вычисляется — из сравнения двух значений. Операторов сравнения шесть:

Оператор Читается как Пример Результат
== равно 5 == 5 True
!= не равно 5 != 3 True
> больше 2 > 7 False
< меньше 2 < 7 True
>= больше или равно 7 >= 7 True
<= меньше или равно 9 <= 4 False

Обратите внимание на два знака равенства в проверке равенства. Это не опечатка и не прихоть — это важнейшее различие, которое подводит почти каждого новичка:

  • =присваивание: «положи это значение в переменную». Команда.
  • ==сравнение: «а эти два значения одинаковые?». Вопрос.
age = 18          # присваиваем: в переменной age теперь 18
print(age == 18)  # спрашиваем: а age равно 18? -> True
print(age == 21)  # спрашиваем: а age равно 21? -> False
print(age != 21)  # спрашиваем: а age НЕ равно 21? -> True

Вывод:

True
False
True

Сравнивать можно не только числа. Строки сравниваются на равенство буква в букву, с учётом регистра:

password = "Kitten"
print(password == "Kitten")  # True
print(password == "kitten")  # False — большая К и маленькая к это разные символы

Первое настоящее условие: if

Теперь соберём всё вместе. Синтаксис (то есть правила записи) минимальный:

temperature = 30

if temperature > 25:
    print("Жарко, пей воду")

print("Программа продолжается")

Вывод:

Жарко, пей воду
Программа продолжается

Разберём построчно:

  1. temperature = 30 — создаём переменную и кладём в неё число 30.
  2. if temperature > 25: — слово if («если»), затем условие, затем двоеточие. Python вычисляет temperature > 25, получает True.
  3. print("Жарко, пей воду") — строка сдвинута вправо на четыре пробела. Этот сдвиг называется отступ (indent). Отступ означает: «эта строка принадлежит условию сверху». Раз условие истинно — строка выполняется.
  4. Пустая строка — просто для читаемости, на работу не влияет.
  5. print("Программа продолжается") — отступа нет, значит строка не принадлежит условию. Она выполнится в любом случае.

Поменяйте temperature = 30 на temperature = 10 и запустите снова. Вывод станет таким:

Программа продолжается

Первая строка исчезла — условие оказалось ложным, и Python просто перепрыгнул через её блок.

Отступы — это синтаксис, а не оформление

Во многих языках блоки кода обозначают фигурными скобками, а отступы делают «для красоты». В Python отступ сам по себе является границей блока. Это первое, что нужно принять и запомнить.

Отступы задают тело условия

Практические правила:

  • Стандартный отступ — 4 пробела. Не 2, не 3, не 8. Так принято, и так делает почти весь мир Python.
  • Не смешивайте пробелы и табуляцию. Внешне они выглядят одинаково, а Python считает их разными и ругается. Нормальный редактор кода (VS Code, PyCharm) по умолчанию превращает Tab в 4 пробела — это то, что нужно.
  • Все строки одного блока должны иметь одинаковый отступ.

Официальное описание — в стандарте оформления кода PEP 8, это главный документ о том, как принято писать на Python.

Вторая ветка: else

else («иначе») — это блок, который выполнится, если условие оказалось ложным. Ровно одна из двух веток сработает всегда: и обе одновременно — никогда.

age = 15

if age >= 18:
    print("Доступ разрешён")
else:
    print("Доступ запрещён: нужно 18 лет")

print("Проверка завершена")

Вывод:

Доступ запрещён: нужно 18 лет
Проверка завершена

Заметьте: у else нет собственного условия. Он не спрашивает «а если наоборот?» — он просто ловит все остальные случаи. Поэтому после else сразу идёт двоеточие, и никаких сравнений между ними быть не может.

Больше двух вариантов: elif

Жизнь редко делится надвое. Оценка бывает отличной, хорошей, средней и плохой. Для таких случаев есть elif — сокращение от else if, «иначе если».

score = 73

if score >= 90:
    grade = "отлично"
elif score >= 75:
    grade = "хорошо"
elif score >= 60:
    grade = "удовлетворительно"
else:
    grade = "неудовлетворительно"

print("Оценка:", grade)

Вывод:

Оценка: удовлетворительно

Вот что здесь критически важно понять — и это самое частое место, где новички путаются.

Python проверяет условия сверху вниз и останавливается на первом истинном. Все остальные ветки после этого пропускаются, даже если они тоже были бы истинны.

Проследим за score = 73:

  1. score >= 90? 73 не больше и не равно 90 → False, идём дальше.
  2. score >= 75? 73 меньше 75 → False, идём дальше.
  3. score >= 60? 73 больше 60 → True! Присваиваем grade = "удовлетворительно" и выходим из всей конструкции.
  4. else не выполняется — до него дело уже не дошло.

Из этого следует практический вывод: порядок веток имеет значение. Если переставить условия от меньшего к большему, всё сломается:

score = 95

if score >= 60:              # 95 >= 60 -> True, срабатывает первая же ветка!
    grade = "удовлетворительно"
elif score >= 90:            # сюда никогда не попадём
    grade = "отлично"

print(grade)                 # выведет: удовлетворительно

Отличник получил тройку. Программа не сломалась и ошибку не показала — она честно сделала то, что написано. Такие ошибки называются логическими: код работает, но неправильно. Их искать сложнее всего, и о том, как это делать, есть отдельная статья — Ошибки и отладка.

Правило: в цепочке elif сначала пишите самые строгие (самые узкие) условия, потом более широкие.

Сколько может быть веток

  • if — обязателен и ровно один.
  • elif — сколько угодно, включая ноль.
  • else — не более одного, и всегда последним.

Соединяем несколько вопросов: and, or, not

Часто решение зависит не от одного факта, а от нескольких сразу. Для этого есть три логических оператора. В Python они называются человеческими словами:

and («и») — истина, только если истинны оба условия.

age = 25
has_ticket = True

if age >= 18 and has_ticket:
    print("Проходите в зал")
else:
    print("Вход невозможен")

Вывод: Проходите в зал. Стоит хоть одному условию стать ложным — сработает else.

or («или») — истина, если истинно хотя бы одно условие.

day = "суббота"

if day == "суббота" or day == "воскресенье":
    print("Выходной!")
else:
    print("Рабочий день")

Вывод: Выходной!

Здесь легко ошибиться и написать if day == "суббота" or "воскресенье":. Так делать нельзя — Python не поймёт это как «или воскресенье». Ниже, в разделе про ошибки, разберём, почему.

not («не») — переворачивает ответ: истину делает ложью и наоборот.

is_banned = False

if not is_banned:
    print("Добро пожаловать")

Вывод: Добро пожаловать. Читается почти как английская фраза: «если не забанен».

Таблица истинности

Полный список исходов удобно держать перед глазами:

A B A and B A or B not A
True True True True False
True False False True False
False True False True True
False False False False True

Ленивая проверка: Python не делает лишней работы

Ещё одна деталь, которая позже вас выручит. Если в A and B левая часть оказалась ложной, результат уже определён — он точно False. Правую часть Python даже не станет вычислять. То же с or: если левая часть истинна, правую он пропустит. Это называется короткое замыкание (short-circuit evaluation).

Зачем это знать? Потому что порядок в and может защитить от ошибки:

name = ""

# Сначала проверяем, что строка не пустая, и только потом лезем в её первый символ
if name != "" and name[0] == "А":
    print("Имя начинается на А")
else:
    print("Не подходит")

Если поменять части местами, программа упадёт на пустой строке: обращение к первому символу несуществующего текста — ошибка. Благодаря короткому замыканию порядок «сначала безопасная проверка, потом рискованная» работает надёжно.

Условия внутри условий

Блок if может содержать внутри себя другой if — это называется вложенностью. Отступ у вложенного блока удваивается.

is_logged_in = True
is_admin = False

if is_logged_in:
    print("Вы вошли в систему")
    if is_admin:
        print("Открыта панель администратора")
    else:
        print("Обычный пользователь")
else:
    print("Пожалуйста, войдите")

Вывод:

Вы вошли в систему
Обычный пользователь

Вложенность работает, но злоупотреблять ею не стоит: после трёх-четырёх уровней код превращается в «лесенку», в которой невозможно разобраться. Часто вложенность можно заменить на and:

# Три уровня вложенности — тяжело читать
if is_logged_in:
    if is_admin:
        if not is_banned:
            print("Панель администратора")

# То же самое одной строкой — гораздо понятнее
if is_logged_in and is_admin and not is_banned:
    print("Панель администратора")

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

Что Python считает «истинным» само по себе

Внутри if можно писать не только сравнение, но и просто значение. Python сам решит, считать его истиной или ложью. Правило простое: «пусто и ноль» — ложь, всё остальное — истина.

Ложными считаются: False, 0, 0.0, пустая строка "", пустой список [], пустой словарь {} и None (специальное значение «ничего»).

name = input("Как вас зовут? ")

if name:                       # то же самое, что name != ""
    print("Привет,", name)
else:
    print("Вы не ввели имя")

Если пользователь просто нажмёт Enter, name окажется пустой строкой — а значит, ложью, и сработает else.

Пользоваться этим удобно, но с осторожностью: if count: и if count > 0: ведут себя одинаково для положительных чисел, но по-разному, если count может быть отрицательным. Когда сомневаетесь — пишите сравнение явно. Явное лучше неявного, это буквально первая строка «Дзена Python».

Типичные ошибки новичков и что означают сообщения

Сообщения об ошибках пугают, потому что написаны по-английски и выглядят как ругань. На самом деле Python довольно вежливо объясняет, что не так. Разберём самые частые случаи дословно.

1. Забыли двоеточие

if age > 18
    print("ok")
SyntaxError: expected ':'

Дословно: «синтаксическая ошибка: ожидалось двоеточие». Python дочитал условие до конца строки и не нашёл :. Лечится добавлением двоеточия.

2. Забыли отступ

if age > 18:
print("ok")
IndentationError: expected an indented block after 'if' statement on line 1

Дословно: «ошибка отступа: ожидался блок с отступом после инструкции if в строке 1». Python увидел if, ждал тело — а тело написано вплотную к краю. Сдвиньте строку на 4 пробела.

3. Написали = вместо ==

if age = 18:
    print("ровно 18")
SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='?

Python прямо подсказывает: «может быть, вы имели в виду ==?». Да, именно это вы и имели в виду. Присваивать внутри if нельзя — там должен быть вопрос, а не команда.

4. Сравнили строку с числом

age = input("Сколько вам лет? ")   # input ВСЕГДА возвращает строку
if age >= 18:
    print("совершеннолетний")
TypeError: '>=' not supported between instances of 'str' and 'int'

Дословно: «ошибка типа: оператор >= не поддерживается между значениями типа str (строка) и int (целое число)». Python не знает, как сравнить текст "18" с числом 18 — для него это разные сущности, как сравнивать длину с весом.

Это, возможно, ошибка №1 у всех новичков. Лечится преобразованием типа:

age = int(input("Сколько вам лет? "))   # int(...) превращает строку в число
if age >= 18:
    print("совершеннолетний")
else:
    print("несовершеннолетний")

5. or с двумя значениями вместо двух условий

day = "среда"
if day == "суббота" or "воскресенье":
    print("Выходной!")

Вывод: Выходной! — хотя среда точно не выходной. Ошибки нет, но результат неверный.

Почему так? Python читает это как (day == "суббота") or ("воскресенье"). Первая часть — False. Вторая часть — непустая строка, а непустая строка считается истиной (см. раздел выше). False or True даёт True. Программа отработала строго по правилам — просто вы попросили не то, что хотели.

Правильно — повторить сравнение полностью:

if day == "суббота" or day == "воскресенье":

Или использовать проверку на вхождение в набор — оператор in, который читается как «содержится в»:

if day in ("суббота", "воскресенье"):
    print("Выходной!")

6. Избыточное сравнение с True

if is_admin == True:     # работает, но многословно
if is_admin:             # так пишут опытные разработчики

is_admin уже является ответом «да/нет» — сравнивать его с True всё равно что спрашивать «правда ли, что правда?».

7. Сравнение дробных чисел на равенство

print(0.1 + 0.2 == 0.3)   # выведет: False

Это не баг Python и не ваша ошибка. Компьютер хранит дробные числа приблизительно (подробности — в статье Как устроен компьютер), и 0.1 + 0.2 даёт 0.30000000000000004. Поэтому дробные числа сравнивают не на точное равенство, а на «достаточную близость»:

result = 0.1 + 0.2
if abs(result - 0.3) < 0.0000001:   # abs(...) — модуль числа, расстояние до нуля
    print("Считаем равными")

Приятная деталь: цепочки сравнений

В большинстве языков «число между 10 и 20» пишут через and. В Python можно писать как в математике — и это законно:

temperature = 15

if 10 <= temperature <= 20:
    print("Комфортная температура")

Это полностью эквивалентно temperature >= 10 and temperature <= 20, просто читается легче. Пользуйтесь.

Собираем всё вместе: маленькая программа

Напишем классификатор возраста — короткий, но использующий всё, что мы прошли.

# Спрашиваем данные у пользователя и сразу превращаем текст в число
age = int(input("Введите ваш возраст: "))

# Отсекаем бессмысленный ввод — так делают в любой настоящей программе
if age < 0 or age > 130:
    print("Похоже, вы ошиблись при вводе")
elif age < 7:
    print("Дошкольник")
elif age < 18:
    print("Школьник")
elif age < 65:
    print("Взрослый")
else:
    print("Пенсионный возраст")

print("Спасибо!")

Пример запуска:

Введите ваш возраст: 14
Школьник
Спасибо!

Ещё один запуск:

Введите ваш возраст: 200
Похоже, вы ошиблись при вводе
Спасибо!

Обратите внимание на первую ветку: проверка на «мусорный» ввод стоит раньше всех остальных. Это распространённый приём — сначала отсеять невозможное, потом разбирать нормальные случаи.

Практика

Задания идут от простого к сложному. Пишите каждое в отдельном файле и обязательно запускайте — понимание приходит от запуска, а не от чтения.

1. Чётное или нечётное

Попросите у пользователя целое число и сообщите, чётное оно или нечётное.

Подсказка: оператор % (он называется «остаток от деления») возвращает то, что осталось после деления. 10 % 2 даёт 0, а 7 % 2 даёт 1. Число чётное ровно тогда, когда остаток от деления на 2 равен нулю.

2. Больше, меньше или равно

Попросите два числа и выведите одну из трёх фраз: «первое больше», «второе больше» или «числа равны».

Подсказка: понадобится if, один elif и else. Подумайте, какая ветка может быть else — та, для которой уже не нужна отдельная проверка.

3. Пускатель в кино

Спросите возраст зрителя и возрастное ограничение фильма (два числа). Пустите зрителя, если возраст не меньше ограничения. Отдельно обработайте случай, когда ограничение — 0: тогда пускать нужно всех, и сообщение должно быть другим: «Фильм для всей семьи».

Подсказка: самое узкое условие — «ограничение равно нулю». Куда его поставить в цепочке?

4. Простой калькулятор

Спросите два числа и знак операции (+, -, *, /) отдельной строкой. Выполните нужное действие и выведите результат. Если знак не распознан — сообщите об этом.

Подсказка: знак операции — это строка, сравнивайте её через ==. И не забудьте про деление на ноль: перед делением проверьте, что второе число не равно нулю, иначе программа упадёт с ZeroDivisionError: division by zero.

5. Високосный год

Спросите год и определите, високосный ли он. Правило такое: год високосный, если он делится на 4, но не делится на 100 — кроме случая, когда он делится на 400 (тогда всё-таки високосный). Проверьте себя: 2024 — високосный, 1900 — нет, 2000 — да.

Подсказка: всё правило умещается в одно условие с and, or и not, но сначала попробуйте записать его вложенными if — так проще увидеть логику. Потом, когда заработает, попробуйте сократить. Это упражнение и на условия, и на аккуратность мышления.

Мини-итог

  • Условие — это развилка: программа задаёт вопрос и в зависимости от ответа идёт по одной из веток.
  • Ответ на вопрос — значение типа bool: True или False.
  • = присваивает, == сравнивает. Их путают все, и все потом привыкают.
  • Отступ в Python — часть синтаксиса. Четыре пробела, единообразно, без табов вперемешку.
  • В цепочке if / elif / else срабатывает ровно одна ветка — первая подошедшая. Поэтому порядок условий важен: узкие проверки идут раньше широких.
  • and, or, not соединяют условия. and и or вычисляются лениво — это можно использовать для защиты от ошибок.
  • Ошибка TypeError: '>=' not supported between instances of 'str' and 'int' почти всегда означает, что вы забыли обернуть input() в int().
  • Логическая ошибка страшнее синтаксической: программа не падает, а тихо делает не то. Проверяйте свои условия на крайних значениях.

Дополнительно почитать: раздел «More Control Flow Tools» в официальном учебнике Python и главу об условиях в Automate the Boring Stuff with Python Эла Свейгарта — книга бесплатно доступна онлайн и написана как раз для начинающих.

Что дальше

Теперь программа умеет выбирать. Следующий шаг — научить её повторять: обрабатывать сотню товаров, тысячу строк файла или каждую букву в слове, не переписывая один и тот же код сто раз. Этим занимаются циклы.

Циклы: как заставить программу повторять действия

Нашли неточность? Выделите фрагмент текста — рядом появится жучок.

Нужен разбор именно вашей ситуации?

Статья описывает общий случай. Если у вас частный — можно разобрать его отдельно, платно. А если не хватает целого материала, предложите тему: её оплачивают вскладчину, и она выходит открытой для всех.

Доска запросов