Поток команд (Control Flow)

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

Для описания изменения порядка инструкций в программе используется термин контроль потока (control flow). Почти во всех языках программирования есть инструкции, позволяющие изменять последовательность выполнения на основании логики и значения переменных.

Условные операторы

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

Однако чаще в программах бывает не так. При выполнении кода, в зависимости от тех или иных условий, некоторые его участки могут быть опущены, в то время как другие - выполнены. Иными словами, в программе может присутствовать ветвление, которое реализуется условным оператором - особой конструкцией языка программирования.

Проведем аналогию с реальность. Человек живет по расписанию. Можно сказать, расписание - это алгоритм для человека, его программный код, подлежащий исполнению. В расписании на 18.00 стоит поход в бассейн. Однако, если воду из бассейна слили, разумно было бы отменить занятие по плаванию, то есть изменить ход выполнения программы-расписания. Одним из условий посещения бассейна должно быть его функционирование, иначе должны выполняться другие действия.

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

if логическое_выражание {
    инструкция 1
    инструкция 2
    ...
}

Перевести на человеческий язык можно так: если логическое выражение возвращает истину, то выполняются выражения внутри фигурных скобок; если логическое выражение возвращает ложь, то код внутри фигурных скобок не выполняется.

Конструкция if логическое_выражение называется заголовком условного оператора. Выражения внутри фигурных скобок - телом условного оператора. Тело может содержать как множество выражений, так и всего одно или даже может быть пустым.

Пример использования условного оператора в Python

if n < 100:
    b = n + a

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

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

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

В примере выше логическим выражением является n < 100. Если оно возвращает истину, то выполнится строчка код b = n + a. Если логическое выражение ложно, то выражение b = n + a не выполнится.

Приведем полную версию программы

b = 0
a = 50
n = 98

if n < 100:
    b = n + a
print(b)

Последняя строчка кода print(b) уже не относится к условному оператору, что обозначено отсутствием перед ней отступа. Она не является вложенной в условный оператор, значит, не принадлежит ему.

Поскольку переменная n равна 98, а это меньше 100, то b станет равной 148. Это значение будет выведено на экран. Если переменная n изначально была бы связана, например, со значением 101, то на экран был бы выведен 0. При n, равной 101, логическое выражение в заголовке условного оператора вернуло бы ложь. Значит, тело не было бы выполнено, и переменная b не изменилась бы.

Структуру программы можно изобразить следующим образом:

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

Для небольших программ иногда чертят так называемые блок-схемы (flowchart), отражающие алгоритм выполнения. В языке блок-схем определенные конструкции обозначаются своими фигурами. Так блок действий обозначается прямоугольником, а логическое выражение - ромбом. Для кода выше блок-схема может выглядеть так

Блок инструкций

Блок инструкций - часть кода, которая сгруппирована и воспринимается как единое целое. Блоки могут состоять из одного или нескольких инструкций, а также могут быть пустыми. В языках C, C++ и некоторых других языках, блоки выделяются фигурными скобками { }. В языке Pascal и некоторых других языках блоки выделяются словами "begin" и "end".

Вложенные инструкции объединяются в блоки по величине отступов. Отступ может быть любым, главное, чтобы в пределах одного вложенного блока отступ был одинаков. Для отступа принято использовать 4 пробела.

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

Основная инструкция:
    Вложенный блок инструкций

Рассмотрим пример кода:

a = 10
b = 5

if a > b:
    print("A больше B")
    print(a - b)

print ("Конец")

Python понимает, какие строки относятся к if на основе отступов. Выполнение блока if a > b заканчивается, когда встречается строка с тем же отступом, что и сама строка if a > b.

Блок else

Часто в программе необходимо выполнить одно действие в том случае, если условие истинно, и другое действие, если оно ложно. С синтаксисом if-else это возможно. Блок if-else в целом похож на оператор if, но секция else определяет действие или набор действий, выполняемых при неудачной проверке.

age = 17

if age >= 18:
    print("Вы можете зарегистрироваться на сайте")
    print("Нажмите эту кнопку для регистрации")
else:
    print("Извините, вы слишком молоды для регистрации")

Если условие в строке 3 истинно, то выполняется первый блок с функцией print(). Если же условие ложно, выполняется блок else в строке 6. Так как значение age меньше 18, условие оказывается ложным и выполняется код в блоке else:

Извините, вы слишком молоды для регистрации

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

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

В случае возврата логическим выражением False поток выполнения программы не возвращается сразу в основную ветку. На случай False существует другой вложенный код, отличный от случая True. Другими словами, встретившись с расширенной версией условного оператора, поток выполнения программы не вернется в основную ветку, не выполнив один из вложенных кодов.

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

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

Если условие при инструкции if оказывается ложным, то выполняется блок кода при инструкции else. Ситуация, при которой бы выполнились обе ветви, невозможна. Либо код, принадлежащий if, либо код, принадлежащий else. Никак иначе. В заголовке else никогда не бывает логического выражения.

Пример кода с веткой else на языке Python

item1 = 50
item2 = 40
if item1 + item2 > 99:
    print("99 гривен недостаточно для оплаты")
else:
    print("чек оплачен")

Нестандартные логические выражения

Следует иметь ввиду, что логическое выражение при if может выглядеть "нестандартно", то есть не так просто, как a > b и тому подобное. Там может стоять просто одна переменная, число, слово True или False, а также сложное логическое выражение, когда два простых соединяются через логически И или ИЛИ

a = ?

if a:
    a = 1

Если вместо знака вопроса будет стоять 0, то с логической точки зрения это False, значит выражение в if не будет выполнено. Если a будет связано с любым другим числом, то оно будет расцениваться как True, и тело условного оператора выполнится. Другой пример:

a = 5 > 0

if a:
    print(a)

Здесь a уже связана с булевым значением. В данном случае это True. Отметим, что в выражении a = 5 > 0 присваивание выполняется после оператора сравнения, так что подвыражение 5 > 0 выполнится первым, после чего результат будет присвоен переменной a. На будущее, если вы сомневаетесь в последовательности выполнения операторов, используйте скобки, например так: a = (5 > 0)

Третий пример:

if a > 0 and a < b:
    print(b - a)

Тут, чтобы вложенный код выполнился, a должно быть больше 0 и одновременно меньше b. Также в Python, в отличие от других языков программирования, позволительна такая сокращенная запись сложного логического выражения

if 0 < a < b:
    print(b - a)

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

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

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

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

  • для посетителей младше 4 лет вход бесплатный;

  • для посетителей от 4 до 18 лет билет стоит 25 гривен;

  • для посетителей от 18 лет и старше билет стоит 40 гривен.

Как использовать команду if для определения платы за вход? Следующий код определяет, к какой возрастной группе относится посетитель, и выводит сообщение со стоимостью билета:

age = 12

if age < 4:
    print("Вход бесплатный")
elif age < 18:
    print("Вход стоит 25 гривен")
else:
    print("Вход стоит 40 гривен")

Условие if в строке 1 проверяет, что возраст посетителя меньше 4 лет. Если условие истинно, то программа выводит соответствующее сообщение и Python пропускает остальные проверки. Оператор elif в строке 3 в действительности является еще одной проверкой if, которая выполняется только в том случае, если предыдущая проверка закончилась неудачей. В этом месте цепочки известно, что возраст посетителя не меньше 4 лет, потом что первое условие было ложным. Если посетителю меньше 18 лет, программа выводит соответствующее сообщение и Python пропускает блок else. Если ложны оба условия - if и elif, то Python выполняет код в блоке else в строке 6.

В данном примере условие в строке 1 дает ложный результат, поэтому его блок не выполняется. Однако второе условие оказывается истинным (12 меньше 18), поэтому код будет выполнен.

Вход стоит 25 гривен

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

Вместо того чтобы выводить сообщение с ценой билета в блоках if-elif-else, лучше использовать другое, более компактное решение: присвоить цену в цепочке if-elif-else, а затем добавить одну команду print после выполнения цепочки:

age = 12

if age < 4:
    price = 0
elif age < 18:
    price = 25
else:
    price = 40
    
print("Вход стоит", price, "гривен")

Строки 4, 6 и 8 присваивают значение price в зависимости от значения age, как и в предыдущем примере. После присваивания цены в цепочке if-elif-else функция print() использует это значение для вывода сообщения с ценой билета.

Этот пример выводит тот же результат, что и предыдущий, но цепочка if-elif-else имеет более четкую специализацию. Вместо того, чтобы определять цену и выводить сообщения, она просто определяет цену билета. Кроме повышения эффективности, у этого кода есть дополнительное преимущество: его легче модифицировать. Чтобы изменить текст выходного сообщения, достаточно будет отредактировать всего одну функцию print() вместо трех разных функций.

Last updated