Логіка та розгалуження
Логіка та розгалуження
Програма, що приймає рішення
До цього уроку програма виконувала рядки один за одним, завжди в одному порядку. Реальні програми реагують на дані: перевіряють пароль, визначають оцінку, обирають дію. Для цього потрібні умови: вирази, результат яких True або False, і розгалуження, яке за умовою вибирає, який код виконувати.
🎯 Мета лекції
- Записувати умови з операторами порівняння й ланцюжками.
- Поєднувати умови через
and,or,notі знати про коротке замикання. - Пояснювати, що значення можуть бути «істинними» чи «хибними».
- Писати розгалуження
if,elif,elseі умовний вираз. - Використовувати
matchдля вибору за шаблоном.
🔑 Ключові терміни
- Умова (condition): вираз, який перевіряють на істинність.
- Розгалуження (branching): вибір коду за умовою.
- Блок (block): група рядків із відступом.
- Коротке замикання (short-circuit): зупинка обчислення, коли результат уже відомий.
- Істинність (truthiness): чи вважає Python значення істинним.
Пригадаємо попередній урок
-4, бо // округлює вниз.str. Число отримують через int() або float().f"{x:.2f}".Порівняння
Оператори порівняння дають результат типу bool: True або False.
| Оператор | Значення | Приклад | Результат |
|---|---|---|---|
== | дорівнює | 5 == 5.0 | True |
!= | не дорівнює | 5 != 4 | True |
< | менше | 3 < 2 | False |
> | більше | 3 > 2 | True |
<= | менше або дорівнює | 3 <= 3 | True |
>= | більше або дорівнює | 2 >= 3 | False |
Числа різних типів порівнюються за значенням: 5 == 5.0 дає True. Порівняти число з рядком за порядком не можна:
print(5 > "3")
TypeError: '>' not supported between instances of 'int' and 'str'
Рядки порівнюються за кодами символів, посимвольно зліва направо. Тому результат не завжди збігається з людською інтуїцією:
print("apple" < "banana", "Ab" < "ab", "10" < "9", 10 < 9)
True True True False
Великі літери мають менші коди, ніж малі, а "10" менше за "9", бо перший символ "1" менший за "9". Для чисел у рядках спершу використовують int().
Ланцюжки порівнянь
Python дозволяє записати подвійну умову як у математиці:
x = 7
print(0 < x < 10)
print(0 < x < 5)
True
False
Запис 0 < x < 10 означає 0 < x and x < 10, причому x обчислюється один раз.

= та ==. Один знак дорівнює присвоює значення, два — порівнюють. Дробові числа через == порівнювати не слід (урок про типи): 0.1 + 0.2 == 0.3 дає False.Логічні оператори
Умови об'єднують трьома операторами:
| Оператор | Значення | Приклад |
|---|---|---|
and | обидві умови істинні | x > 0 and x < 10 |
or | хоча б одна істинна | x < 0 or x > 10 |
not | заперечення | not x > 5 |
print(True and False, True or False, not True)
False True False
Пріоритет: not вищий за and, а and вищий за or. Вираз 1 == 2 or 3 == 3 and 4 == 4 обчислюється як 1 == 2 or (3 == 3 and 4 == 4) і дає True. Для читабельності складні умови беруть у дужки.
Перевірка належності через in:
print("a" in "abc", "z" not in "abc", 3 in [1, 2, 3])
True True True
Коротке замикання
Python обчислює and та or зліва направо і зупиняється, щойно результат відомий:
A and B: якщоAхибне, результат уже відомий,Bне обчислюється;A or B: якщоAістинне, результат відомий,Bне обчислюється.
def f():
print("f викликана")
return 1
print(0 and f())
print(1 and f())
print(1 or f())
print(0 or f())
0
f викликана
1
1
f викликана
1

Це корисно для захисту від помилок: у виразі n != 0 and 10 / n > 1 ділення виконується, лише якщо n не нуль.
and і or повертають операнд
Важлива особливість Python: and і or повертають не True чи False, а один зі своїх операндів:
A or BповертаєA, якщоAістинне, інакшеB;A and BповертаєA, якщоAхибне, інакшеB.
print(0 or "default", "" or "Гість", "a" or "b")
print(5 and 7, 0 and 7)
default Гість a
7 0
Тому name or "Гість" — поширений спосіб задати значення за замовчуванням. Простежте це в трасувальнику:
Після рядка shown = name or "Гість" змінна shown вказує на об'єкт 'Гість', бо порожній рядок хибний. Рядок count and 10 / count не викликає ділення на нуль: count дорівнює 0, тож and повертає його одразу.
Істинність значень
Умову можна записати не лише як порівняння: будь-яке значення Python вважає істинним або хибним. Хибні такі значення:
| Значення | Тип |
|---|---|
False | bool |
0, 0.0 | int, float |
"" | порожній рядок |
[], (), {}, set() | порожні колекції |
None | NoneType |
Усі інші значення істинні. Функція bool() показує це:
print(bool(0), bool(0.0), bool(""), bool([]), bool(None))
print(bool("0"), bool([0]), bool(-1))
False False False False False
True True True
Рядок "0" і список [0] не порожні, тому істинні. Завдяки цьому можна писати if name: замість if name != "":.
Розгалуження if, elif, else
Інструкція if виконує блок коду, лише якщо умова істинна:
age = 17
if age >= 18:
print("Доступ дозволено")
else:
print("Доступ заборонено")
Доступ заборонено
Синтаксис має три обов'язкові елементи:
- після умови стоїть двокрапка
:; - рядки блоку мають відступ (4 пробіли), і лише відступ показує, що рядок належить блоку;
elseне має умови: він виконується, коли жодна умова вище не спрацювала.
Щоб перевірити кілька варіантів, між if і else ставлять elif (від else if):
score = 82
if score >= 90:
grade = "A"
elif score >= 75:
grade = "B"
elif score >= 60:
grade = "C"
else:
grade = "F"
print(grade)
B
Python перевіряє умови зверху вниз і виконує перший блок, умова якого істинна. Решта пропускаються, навіть якщо їхні умови теж були б істинними. Бал 82 задовольняє і >= 75, і >= 60, але виконується лише B.

У трасувальнику видно, що рядок grade = "A" пропущений, а після перевірки score >= 75 виконується grade = "B".
if поспіль — це незалежні перевірки, а if + elif — одна перевірка, у якій спрацює лише одна галузь. Для x = 5 код if x > 3: ... і if x > 1: ... виведе обидві галузі, а з elif — лише першу.Вкладені умови та pass
Блок може містити інші if. Кожен рівень вкладеності додає відступ:
age = 20
has_ticket = True
if age >= 18:
if has_ticket:
print("Прохід дозволено")
else:
print("Потрібен квиток")
Прохід дозволено
Глибоку вкладеність краще замінювати об'єднанням умов: if age >= 18 and has_ticket:. Порожній блок записують словом pass (інструкція, що нічого не робить).
Умовний вираз
Коли потрібно вибрати між двома значеннями, зручний умовний вираз (conditional expression):
age = 17
status = "дорослий" if age >= 18 else "неповнолітній"
print(status)
неповнолітній
Форма: значення_якщо_істина if умова else значення_якщо_хиба. Це вираз, тому його можна підставити будь-де, де потрібне значення.
Типові помилки синтаксису
= замість ==
x = 5
if x = 5:
print(1)
SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='?
Відсутня двокрапка
if x == 1
print(1)
SyntaxError: expected ':'
Помилки відступів
Блок без відступу:
if True:
print(1)
IndentationError: expected an indented block after 'if' statement on line 1
Нерівний відступ:
if True:
print(1)
print(2)
IndentationError: unindent does not match any outer indentation level
Редактор зазвичай ставить відступ автоматично, а для переходів на новий рівень використовують клавішу Tab. Змішувати пробіли й табуляцію в одному файлі не слід.
match: вибір за шаблоном
Коли одне й те саме значення порівнюють з багатьма варіантами, ланцюжок elif повторює порівняння знову й знову:
command = "stop"
if command == "go":
print("їдемо")
elif command == "stop" or command == "halt":
print("зупиняємось")
elif command == "back":
print("назад")
else:
print("невідома команда")
зупиняємось
Для таких випадків у Python є інструкція match. Вона бере одне значення й порівнює його зі шаблонами (patterns) по черзі. Розглянемо її поступово, від найпростішого до складнішого.
Простий match
Той самий приклад із match:
command = "stop"
match command:
case "go":
print("їдемо")
case "stop" | "halt":
print("зупиняємось")
case "back":
print("назад")
case _:
print("невідома команда")
зупиняємось
Будова інструкції:
match command:— значення, яке перевіряємо, і двокрапка;- кожен
case шаблон:— один варіант, після нього блок з відступом; - Python порівнює значення з шаблонами зверху вниз і виконує блок першого збігу; решта пропускаються;
- шаблон
_(підкреслення) збігається з будь-яким значенням, тому його ставлять останнім як «усе інше» (аналогelse).
Простежте виконання в трасувальнику:
Шаблон "go" не збігся, шаблон "stop" | "halt" збігся, тому виконано лише його блок, а case _ пропущено.
Що буде, якщо збігу немає
Блок case _ не обов'язковий. Якщо жоден шаблон не підійшов, match нічого не робить, і програма йде далі:
day = 3
match day:
case 1:
print("понеділок")
case 6:
print("субота")
print("після match")
після match
Для day = 6 вивід був би субота, а потім після match.
Кілька значень в одному case
Знак | читається як «або». Він об'єднує кілька шаблонів в один блок:
for d in (1, 5, 6, 7):
match d:
case 6 | 7:
print(d, "вихідний")
case _:
print(d, "робочий")
1 робочий
5 робочий
6 вихідний
7 вихідний
Це коротше за if d == 6 or d == 7:.
Захоплення значення
Шаблон може бути ім'ям. Тоді він збігається з будь-яким значенням і записує його в цю змінну:
point = 42
match point:
case 0:
print("нуль")
case n:
print("число", n)
число 42
Тут n — не порівняння з наявною змінною, а нова змінна, яку створює шаблон. Відмінність від _: підкреслення значення не зберігає, а ім'я зберігає.
Оскільки ім'я збігається з усім, шаблон з голим іменем має бути останнім. Інакше Python відхиляє код:
match 5:
case x:
print(x)
case 1:
print(1)
SyntaxError: name capture 'x' makes remaining patterns unreachable
Додаткова умова (guard)
Після шаблону можна дописати if з умовою. Блок виконається, лише якщо шаблон збігся і умова істинна:
for t in (-5, 0, 20, 35):
match t:
case n if n < 0:
print(n, "мороз")
case 0:
print(n, "нуль")
case n if n <= 25:
print(n, "тепло")
case _:
print(t, "спека")
-5 мороз
0 нуль
20 тепло
35 спека
Ім'я n захоплює значення, а if перевіряє його. Якщо умова хибна, Python переходить до наступного case.
Шаблони для кортежів
Кортеж (tuple) — впорядкований набір значень у круглих дужках, наприклад ("move", 3). Докладно кортежі розглянемо в уроці про колекції. Тут вони потрібні, бо match уміє порівнювати структуру значення і витягувати з неї частини.
Команда складається з назви й, можливо, параметрів. Шаблон описує форму кортежу:
for cmd in (("stop",), ("move", 3), ("move", 3, 4), ("jump",)):
match cmd:
case ("stop",):
print(cmd, "стоп")
case ("move", steps):
print(cmd, "крок", steps)
case ("move", x, y):
print(cmd, "до точки", x, y)
case _:
print(cmd, "невідома команда")
('stop',) стоп
('move', 3) крок 3
('move', 3, 4) до точки 3 4
('jump',) невідома команда
Правила:
- літерали (
"move") мають збігтися точно; - імена (
steps,x,y) захоплюють відповідні елементи; - кількість елементів теж має збігтися:
("move", steps)не підходить для кортежу з трьох значень, тому для нього спрацював третійcase.
Ще один приклад: положення точки на площині.
point = (3, 0)
match point:
case (0, 0):
print("початок координат")
case (x, 0):
print("на осі X, x =", x)
case (0, y):
print("на осі Y, y =", y)
case (x, y):
print("точка", x, y)
на осі X, x = 3
Шаблони перевіряються по черзі: (0, 0) не збігся, а (x, 0) збігся, бо другий елемент дорівнює нулю, а перший захоплено в x.
Перевірка типу
Шаблон тип() збігається, якщо значення має цей тип. Дужки обов'язкові:
for v in (7, 3.5, "текст", True, None):
match v:
case bool():
print(repr(v), "логічне")
case int():
print(repr(v), "ціле")
case float():
print(repr(v), "дробове")
case str():
print(repr(v), "рядок")
case None:
print(repr(v), "None")
7 ціле
3.5 дробове
'текст' рядок
True логічне
None None
Порядок важливий: bool — підтип int (урок про типи), тому True збігся б і з int(). Тому bool() стоїть перед int(). Шаблон None пишеться без дужок: це літерал.
Тип можна поєднати з іменем через as усередині структури:
match ("move", 5):
case ("move", int() as steps):
print("кроків:", steps)
кроків: 5
Пастка: ім'я в case не порівнюється зі змінною
Найпоширеніша помилка: спроба порівняти значення зі змінною через case ім'я. Python сприймає ім'я як шаблон захоплення, а не як порівняння:
RED = 1
color = 2
match color:
case RED:
print("RED тепер дорівнює", RED)
RED тепер дорівнює 2
Хоча color не дорівнює 1, блок виконався, а змінну RED перезаписано. Порівнювати зі змінною в case напряму не можна: використовують літерали або умову case n if n == RED.
Приклад: калькулятор
Об'єднаємо введення, перетворення та match:
a = float(input("a: "))
b = float(input("b: "))
op = input("Операція (+ - * /): ")
match op:
case "+":
print(a + b)
case "-":
print(a - b)
case "*":
print(a * b)
case "/":
print(a / b)
case _:
print("невідома операція")
Коли що вибирати
| Ситуація | Інструмент |
|---|---|
Умова з діапазонами й порівняннями (score >= 75) | if / elif |
Складна логіка з and, or, not | if / elif |
| Одне значення проти кількох точних варіантів | match |
| Потрібно розібрати структуру (кортеж, тип) і витягти частини | match |
match схожі на помилки в if: пропущена двокрапка дає SyntaxError: expected ':', а case без відступу — IndentationError: expected an indented block after 'match' statement on line 2. Альтернативи, що прив'язують різні імена (case (a, b) | (a,):), заборонені: SyntaxError: alternative patterns bind different names.Підсумок
- Порівняння (
==,!=,<,>,<=,>=) даютьbool. Ланцюжок0 < x < 10— дві перевірки разом. and,or,notоб'єднують умови. Пріоритет:not,and,or.andтаorзупиняються, коли результат відомий, і повертають один з операндів.- Хибні значення:
False,0,0.0,"", порожні колекції,None. Решта істинні. if/elif/elseперевіряють умови зверху вниз і виконують перший істинний блок. Блок позначає відступ.a if умова else b— умовний вираз.matchпорівнює значення з шаблонами по черзі: літерали,|, імена-захоплення, умоваif, кортежі, типи._означає «усе інше».
Типові хибні уявлення
0 or "x" дає "x", а не True.elif та else пропускаються.SyntaxError. Порівняння записують через ==."0" і "False" — непорожні, тому істинні.Передбачте, перш ніж запускати
print(0 or "x", 3 and 4, None or 0)
x 4 0
0 or "x" повертає другий операнд, 3 and 4 — другий (бо перший істинний), None or 0 — другий.
print(1 < 2 < 3, 3 > 2 > 2)
True False
Другий ланцюжок: 3 > 2 and 2 > 2, а друга частина хибна.
x = 5
if x > 3:
print("a")
elif x > 1:
print("b")
else:
print("c")
Що зміниться, якщо elif замінити на if?
a
З elif виконується лише перший істинний блок. Якщо замінити на if, умови стануть незалежними, і вивід буде a та b.
print(not 1 == 2)
True
Спершу 1 == 2 дає False, потім not False дає True.
x = 3
match x:
case 1 | 2:
print("a")
case n if n > 2:
print("b", n)
case _:
print("c")
b 3
Шаблон 1 | 2 не збігся. Ім'я n захопило 3, а умова n > 2 істинна, тому виконано другий блок.
Практичні завдання
A (від 90), B (від 75), C (від 60), інакше F.score = int(input("Бал: "))
if score >= 90:
print("A")
elif score >= 75:
print("B")
elif score >= 60:
print("C")
else:
print("F")
так або ні. Перевірте на 1900, 2000, 2023, 2024.year = int(input("Рік: "))
if year % 4 == 0 and (year % 100 != 0 or year % 400 == 0):
print("так")
else:
print("ні")
Для 1900 та 2023 виведе ні, для 2000 і 2024 — так.
вага / зріст ** 2 і виведіть категорію: менше 18.5 — «недостатня», менше 25 — «норма», менше 30 — «надлишкова», інакше — «ожиріння». Виведіть також значення з одним знаком після крапки.weight = float(input("Вага, кг: "))
height = float(input("Зріст, м: "))
bmi = weight / height ** 2
if bmi < 18.5:
category = "недостатня"
elif bmi < 25:
category = "норма"
elif bmi < 30:
category = "надлишкова"
else:
category = "ожиріння"
print(f"{bmi:.1f}: {category}")
Для 70 і 1.75 результат: 22.9: норма.
n. Виведіть FizzBuzz, якщо n ділиться на 15; Fizz, якщо на 3; Buzz, якщо на 5; інакше саме число. Спершу подумайте, у якому порядку розташувати умови.n = int(input("n: "))
if n % 15 == 0:
print("FizzBuzz")
elif n % 3 == 0:
print("Fizz")
elif n % 5 == 0:
print("Buzz")
else:
print(n)
Умову на 15 ставлять першою: число 15 ділиться і на 3, і на 5, і за іншого порядку спрацювала б хибна галузь.
while, for, range, break і continue.Вирази, оператори, введення і перетворення типів
Арифметичні вирази та пріоритет операторів, ділення націло й остача з від'ємними числами, скорочені оператори, введення через input, перетворення типів int, float, str, bool та форматування виводу через f-рядки.
Цикли та ітерація
Цикл while з умовою, цикл for як прохід по ітерованому об'єкту, функція range, інструкції break, continue і else у циклах, вкладені цикли та як зупинити нескінченний цикл.