if — оператор розгалуження

Порядок дій алгоритму може бути нелінійним. Іноді потрібно обрати з двох і більше варіантів гілок алгоритму.

Оператор розгалуження if дозволяє обрати одну з гілок алгоритму на підставі виконання або невиконання заданої умови.

Загальний випадок запису

У загальному випадку оператор розгалуження if записується наступним чином:

if <умова>:
    <блок коду  1, якщо умова == True>
else:
    <блок коду  2, якщо умова == False>

<наступні оператори>

Як інтерпретатор Python обробляє оператор розгалуження if?

  1. На першому кроці обчислюється значення виразу <умова>.
  2. Якщо результат обчислення дорівнює True, то виконається блок коду № 1, який слідує одразу після рядка if <умова>:
  3. Якщо результат обчислення дорівнює False, то виконається блок коду № 2, який слідує одразу після рядка else:.
  4. Після виконання блоку № 1 або блоку № 2 будуть виконані наступні оператори.
digraph VotingEligibility {
  node [shape=box fontname="Helvetica" fontsize="12" color="#87D0F5" penwidth=2];
  edge [fontname="Helvetica" fontsize="12" color="#87D0F5" penwidth=2];

  start     [label="попередні оператори"];
  check     [shape=diamond label="умова"];
  allow     [label="блок коду № 1"];
  deny      [label="блок коду № 2"];
  end       [label="наступні оператори"];

  start -> check;
  check -> allow [label="True"];
  check -> deny [label="False"];
  allow -> end;
  deny -> end;
}

⚠️ Важливо: в операторі if виконається або блок коду № 1, або блок коду № 2, але не обидва одразу! Не існує такої умови, щоб виконувались обидва блоки.

Іноді можна зустріти таку форму, коли немає другого блоку коду:

if <умова>:
    <блок коду  1, якщо умова == True>

<наступні оператори>

У цьому випадку, якщо результат обчислення виразу <умова> дорівнює False, то будуть виконані одразу <наступні оператори>:

digraph VotingEligibility {
  node [shape=box fontname="Helvetica" fontsize="12" color="#87D0F5" penwidth=2];
  edge [fontname="Helvetica" fontsize="12" color="#87D0F5" penwidth=2];

  start     [label="попередні оператори"];
  check     [shape=diamond label="умова"];
  allow     [label="блок коду № 1"];
  end       [label="наступні оператори"];

  start -> check;
  check -> allow [label="True"];
  check -> end [label="False"];
  allow -> end;
}

На місці виразу <умова> може бути:

  • константи False або True
    • if True:
    • if False:
  • імена змінних булевого типу
    • if not_found:
  • вирази рівності або нерівності, порівняння чисел, рядків, списків: ==, !=, >, <, <=, >=:
    • if count == 0
    • if sum != 100
    • if age >= 18
    • if name == "John"
  • входження елемента в послідовність: in
    • if student_name in list_of_best_students:
  • складені вирази з операторами or, and:
    • if radius > 0 and distance > 0
  • виклики різних функцій або методів:
    • if get_deсision()
    • if some_object.some_method()
  • або комбінації вищезгаданих прикладів за допомогою операторів or, and, not.

У прикладі нижче, програма запитує вік користувача, і залежно від умови age >= 18:

age = int(input("Вік: "))
if age >= 18:
    print("Можна голосувати")
else:
    print('Не можна голосувати')
digraph VotingEligibility {
  node [shape=box fontname="Helvetica" fontsize="12" color="#87D0F5" penwidth=2];
  edge [fontname="Helvetica" fontsize="12" color="#87D0F5" penwidth=2];

  start     [shape=oval label="Початок"];
  input     [shape=parallelogram label="age"];
  check     [shape=diamond label="age >= 18"];
  allow     [shape=parallelogram label="Можна голосувати"];
  deny      [shape=parallelogram label="Не можна голосувати"];
  end       [shape=oval label="Кінець"];

  start -> input;
  input -> check;
  check -> allow [label="True"];
  check -> deny [label="False"];
  allow -> end;
  deny -> end;
}

Іноді бувають більш складні розгалуження, коли потрібно обрати не два альтернативних шляхи, а більше.

age: int = int(input("Вік: "))
if age <= 5:
    # 1, 2, 3, 4, 5
    print("Дитячий садок")
elif age <= 16:
    # 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
    print("Школа")
elif age <= 21:
    # 17, 18, 19, 20, 21
    print("Університет")
else:
    # 22 і більше
    print("Доросле життя")

Блок-схема алгоритму для цього прикладу показана на рисунку нижче:

digraph CFG {
  node [shape=box fontname="Helvetica" fontsize="12" color="#87D0F5" penwidth=2];
  edge [fontname="Helvetica" fontsize="12" color="#87D0F5" penwidth=2];

  start [shape=oval label="Початок"];
  input_age [shape=parallelogram label="age"];
  cond1 [shape=diamond label="age <= 5"];
  print_kindergarten [shape=parallelogram label="Дитячий садок"];
  cond2 [shape=diamond label="age <= 16"];
  print_school [shape=parallelogram label="Школа"];
  cond3 [shape=diamond label="age <= 21"];
  print_university [shape=parallelogram label="Університет"];
  print_adult [shape=parallelogram label="Доросле життя"];
  end [shape=oval label="Кінець"];

  start -> input_age;
  input_age -> cond1;
  cond1 -> print_kindergarten [label="True"];
  cond1 -> cond2 [label="False"];
  print_kindergarten -> end;

  cond2 -> print_school [label="True"];
  cond2 -> cond3 [label="False"];
  print_school -> end;

  cond3 -> print_university [label="True"];
  cond3 -> print_adult [label="False"];
  print_university -> end;
  print_adult -> end;
}

Ледаче обчислення умов

У Python умовні вирази в операторі if виконуються за принципом ледачого обчислення (lazy evaluation), коли використовується логічні оператори and та or. Це означає, що Python припиняє перевірку умов щойно результат стає відомим. Наприклад, у виразі if a and b: значення b не буде обчислено, якщо a вже є False, адже вся умова не може бути True. Аналогічно, у виразі if a or b:, якщо a є True, Python не перевірятиме b. Це дозволяє уникнути зайвих обчислень і, що важливо, може запобігти помилкам — наприклад, якщо друга умова викликає функцію, яка не має сенсу, якщо перша не виконалась. Така поведінка часто використовується для безпечного доступу до об’єктів, які можуть бути None.

Уявіть, що ви питаєте друга:

— Чи ми йдемо гуляти, якщо зараз не дощить і у тебе є настрій?

Якщо він каже: «Йде дощ» — ви навіть не будете питати про настрій. Це і є ледаче обчислення: немає сенсу перевіряти другу умову, якщо перша вже дає відповідь.

Ось приклади, які демонструють ледаче обчислення умов в операторі if у Python:

✅ Позитивний приклад:

user = None

# Тут перевірка user is not None відбувається першою
# Якщо user — None, то друга частина не буде виконуватись
if user is not None and user.is_active():
    print("Користувач активний")

У цьому прикладі, якщо user є None, то виклик user.is_active() не буде виконано, що запобігає помилці AttributeError.

❌ Негативний приклад (без ледачого обчислення)

user = None

# Тут Python намагається обчислити обидві частини одразу
# Це призведе до помилки, бо user — None
if user.is_active() and user is not None:
    print("Користувач активний")

У цьому випадку виникне помилка AttributeError, оскільки user.is_active() викликається до перевірки user is not None.

Приведення різних об'єктів до bool

Оператор if очікує, що значення <умова> буде булевого типу (bool). Не завжди програмісти утруднюють себе написанням коректного коду і підставляють у <умова> значення відмінного від bool типу. У цьому випадку інтерпретатор Python робить неявне приведення типів до bool.

У прикладі нижче value — посилається на об'єкт типу str (рядок). При цьому ж value використовується як умова в операторі if. Тут інтерпретатор буде неявно приводити значення value (рядковий тип) до булевого типу (bool)

value: str = input("Введіть ім'я:")
if value:
    print("Добрий день", value)
else:
    print("Ви ввели порожній рядок")

У таблиці нижче показані різні не-булеві значення, а також коректний запис для використання в умовному операторі if:

Значення value Пояснення Очікуване Коректний запис
0 нуль цілочисельний False value == 0
0.0 нуль дійсний False value == 0.0
[] порожній список False len(value) == 0
{} порожній словник False len(value) == 0
() порожній кортеж False len(value) == 0
"" порожній рядок False len(value) == 0
None об'єкт None False value is None

⚠️ Увага! Неявне приведення типів в умові оператора if — поганий тон! Уникайте неявного приведення типів!