Множественное ветвление: if-elif-else

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

Рассмотрим конкретный пример. Допустим, в зависимости от возраста пользователя, ему рекомендуется определенный видеоконтент. При этом выделяют группы от 3 до 6 лет, от 6 до 12, от 12 до 16, 16+. Итого 4 диапазона. Как бы мы стали реализовывать задачу, имея в наборе инструментов только конструкцию if-else?

Самый простой ответ – последовательно проверять вхождение введенного числа-возраста в определенный диапазон с помощью следующих друг за другом условных операторов:

old = int(input('Ваш возраст: '))
 
print('Рекомендовано:', end=' ')
 
if 3 <= old < 6:
    print('"Заяц в лабиринте"')
 
if 6 <= old < 12:
    print('"Марсианин"')
 
if 12 <= old < 16:
    print('"Загадочный остров"')
 
if 16 <= old:
    print('"Поток сознания"')

Примечание. Названия фильмов выводятся на экран в двойных кавычках. Поэтому в программе для определения строк используются одинарные.

Предложенный код прекрасно работает, но есть одно существенное "но". Он не эффективен, так как каждый if в нем – это отдельно взятый оператор, никак не связанный с другими if. Процессор тратит время и "нервы" на обработку каждого из них, даже если в этом уже нет необходимости. Например, введено число 10. В первом if логическое выражение возвращает ложь, и поток выполнения переходит ко второму if. Логическое выражение в его заголовке возвращает истину, и его тело выполняется. Всё, на этом программа должна была остановиться.

Однако следующий if никак не связан с предыдущим, поэтому далее будет проверяться вхождение значения переменной old в диапазон от 12 до 16, в чем необходимости нет. И далее будет обрабатываться логическое выражение в последнем if, хотя уже понятно, что и там будет False. Что же делать?

Ответом является вложение условных операторов друг в друга:

old = int(input('Ваш возраст: '))
 
print('Рекомендовано:', end=' ')
 
if 3 <= old < 6:
    print('"Заяц в лабиринте"')
else:
    if 6 <= old < 12:
        print('"Марсианин"')
    else:
        if 12 <= old < 16:
            print('"Загадочный остров"')
        else:
            if 16 <= old:
                print('"Поток сознания"')

Рассмотрим поток выполнения этого варианта кода. Сначала проверяется условие в первом if (он же самый внешний). Если здесь было получено True, то тело этого if выполняется, а в ветку else мы даже не заходим, так как она срабатывает только тогда, когда в условии if возникает ложь.

Если внешний if вернул False, поток выполнения программы заходит в соответствующий ему внешний else. В его теле находится другой if со своим else. Если введенное число попадает в диапазон от 6 до 12, то выполнится тело вложенного if, после чего программа завершается. Если же число не попадает в диапазон от 6 до 12, то произойдет переход к ветке else. В ее теле находится свой условный оператор, имеющий уже третий уровень вложенности.

Таким образом до последней проверки (16 <= old) интерпретатор доходит только тогда, когда все предыдущие возвращают False. Если же по ходу выполнения программы возникает True, то все последующие проверки опускаются, что экономит ресурсы процессора. Кроме того, такая логика выполнения программы более правильная.

Теперь зададимся следующим вопросом. Можно ли как-то оптимизировать код множественного ветвления и не строить лестницу из вложенных друг в друга условных операторов? Во многих языках программирования, где отступы используются только для удобства чтения программистом, но не имеют никакого синтаксического значения, часто используется подобный стиль:

if логическое_выражение {
    … ;
}
else if логическое_выражение {
    … ;
}
else if логическое_выражение {
    … ;
}
else {
    … ;
}

Может показаться, что имеется только один уровень вложенности, и появляется новое расширение для if, выглядящее как else if. Но это только кажется. На самом деле if, стоящее сразу после else, является вложенным в это else. Выше приведенная схема – то же самое, что

if логическое_выражение {
    … ;
}
else
    if логическое_выражение {
        … ;
    }
    else
        if логическое_выражение {
            … ;
        }
        else {
            … ;
        }

Именно так ее "понимает" интерпретатор или компилятор. Однако считается, что человеку проще воспринимать первый вариант.

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

Слово "elif" образовано от двух первых букв слова "else", к которым присоединено слово "if". Это можно перевести как "иначе если".

В отличие от else, в заголовке elif обязательно должно быть логическое выражение также, как в заголовке if. Перепишем нашу программу, используя конструкцию множественного ветвления:

old = int(input('Ваш возраст: '))
 
print('Рекомендовано:', end=' ')
 
if 3 <= old < 6:
    print('"Заяц в лабиринте"')
elif 6 <= old < 12:
    print('"Марсианин"')
elif 12 <= old < 16:
    print('"Загадочный остров"')
elif 16 <= old:
    print('"Поток сознания"')

Обратите внимание, в конце, после всех elif, может использоваться одна ветка else для обработки случаев, не попавших в условия ветки if и всех elif. Блок-схему полной конструкции if-elif-…-elif-else можно изобразить так:

Как только тело if или какого-нибудь elif выполняется, программа сразу же возвращается в основную ветку (нижний ярко-голубой прямоугольник), а все нижеследующие elif, а также else пропускаются.

Практическая работа

  1. Спишите последний вариант кода программы из урока. Дополните ее веткой else, обрабатывающие случаи, когда пользователь вводит числа не входящие в заданные четыре диапазона. Подумайте, почему в первой версии программы (когда использовались не связанные друг с другом условные операторы) нельзя было использовать else, а для обработки таких, не входящих в диапазоны, случаев пришлось бы писать еще один if?

  2. Усовершенствуйте предыдущую программу, обработав исключение ValueError, возникающее, когда вводится не целое число.

  3. Напишите программу, которая запрашивает на ввод число. Если оно положительное, то на экран выводится цифра 1. Если число отрицательное, выводится -1. Если введенное число – это 0, то на экран выводится 0. Используйте в коде условный оператор множественного ветвления.

Last updated