Сравнения и логика
Теория
Почти каждое решение в программе — это вопрос с ответом «да» или «нет»: товар в наличии? заказ оплачен? сумма больше порога? Операторы сравнения (==, !=, <, >, <=, >=) отвечают на такие вопросы и возвращают bool — True или False. Логические операторы and, or, not собирают из простых условий сложные: «активен и есть на складе».
У логики в Python две особенности, на которых часто ошибаются. Первая — истинность: в условиях можно использовать не только True/False, но и любые значения; 0, "" и None считаются ложными, остальное — истинным. Вторая — ленивое вычисление: and и or вычисляют правую часть, только если без неё ответ неизвестен, и возвращают один из операндов, а не обязательно bool.
Наглядно
Таблица 1. Операторы сравнения на данных магазина.
| Оператор | Смысл | Пример | Результат |
|---|---|---|---|
== |
равно | status == "paid" при status = "paid" |
True |
!= |
не равно | status != "cancelled" |
True |
< > |
меньше, больше | stock > 0 при stock = 12 |
True |
<= >= |
меньше или равно, больше или равно | total >= 3000 при total = 2999 |
False |
| цепочка | значение в диапазоне | 1000 <= price <= 5000 при price = 1499 |
True |
Таблица 2. Логические операторы: результат для всех сочетаний a и b.
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 |
Таблица 3. Какие значения считаются ложными. Всё, чего нет в таблице, — истинно (в том числе "0", "False", -1).
| Значение | Тип | Пример в магазине |
|---|---|---|
False |
bool |
is_active = False |
None |
NoneType |
скидка не назначена |
0, 0.0 |
int, float |
остаток закончился |
"" |
str |
поле формы не заполнено |
На практике
Задача: решить, можно ли показать кнопку «Купить»: товар активен, есть на складе и цена в бюджете покупателя.
Шаг 1. Сравниваем числа
Сравнение возвращает bool, его можно сохранить в переменную:
stock = 12 price = 1499 budget = 5000 in_stock = stock > 0 affordable = price <= budget print(in_stock, affordable)
Результат:
True True
Шаг 2. Сравниваем строки
Строки сравниваются посимвольно и с учётом регистра:
status = "Paid" print(status == "paid", status.lower() == "paid") print("10" < "9")
Результат:
False True True
"10" < "9" — потому что сравниваются символы: "1" меньше "9". Числа, пришедшие строками, перед сравнением приводят к числам.
Шаг 3. Проверяем диапазон цепочкой
Python позволяет писать сравнения цепочкой, как в математике:
print(1000 <= price <= 5000)
Результат:
True
Это то же самое, что 1000 <= price and price <= 5000.
Шаг 4. Объединяем условия
Кнопка «Купить» доступна, если товар активен и есть на складе и по карману:
is_active = True can_buy = is_active and stock > 0 and price <= budget show_badge = not is_active or stock == 0 print(can_buy, show_badge)
Результат:
True False
show_badge — плашка «нет в продаже»: товар неактивен или закончился.
Шаг 5. Расставляем скобки
Приоритет: сначала сравнения, потом not, потом and, потом or. Без скобок смысл может поменяться:
status = "paid" is_express = False print(status == "paid" or status == "shipped" and is_express) print((status == "paid" or status == "shipped") and is_express)
Результат:
True False
Первая строка читается как paid or (shipped and express). Если имелось в виду «оплачен или отправлен, и при этом экспресс» — нужны скобки.
Шаг 6. Проверяем истинность значений
bool() показывает, как значение поведёт себя в условии:
print(bool(0), bool(12), bool(""), bool("0"), bool(None))
Результат:
False True False True False
Шаг 7. Пользуемся ленивым вычислением
and не вычисляет правую часть, если левая ложна. Это защищает от ошибки, когда остаток неизвестен:
stock = None available = stock is not None and stock > 0 print(available) print("" or "Гость", 0 and 100)
Результат:
False Гость 0
stock > 0 при stock = None упал бы с TypeError, но до него дело не дошло. Вторая строка показывает, что or и and возвращают операнд: "" or "Гость" — первое истинное значение, 0 and 100 — первое ложное.
Частые ошибки
x == "a" or "b". Читается как(x == "a") or "b", а непустая строка"b"всегда истинна — условие всегда выполняется. Правильно:x == "a" or x == "b".- Сравнение чисел-строк.
"10" < "9"—True. Сначалаint(). - Сравнение
Noneс числом.None > 0—TypeError. Сначалаis not None, потом сравнение —andсам остановится. orдля значения по умолчанию.discount or 10заменит на 10 не толькоNone, но и честный0. Как это исправить — в теме «Условия».=вместо==.=— присваивание; в условииif x = 5:—SyntaxError.
Итог
Сравнения
== != < > <= >=возвращаютbool.- Цепочки:
1000 <= price <= 5000. - Строки — посимвольно и с учётом регистра; числа-строки сначала приводим к числам.
Логика
and— все условия,or— хотя бы одно,not— отрицание.- Приоритет: сравнения →
not→and→or; при смешивании — скобки.
Истинность
- Ложны:
False,None,0,0.0,""(и пустые коллекции); остальное истинно.
Ленивое вычисление
a and b: еслиaложно,bне вычисляется → защитаx is not None and x > 0.and/orвозвращают операнд:name or "Гость".
Вопросы на собеседовании
Что вернёт 0 or "default" и 5 and 0?
"default" и 0. or возвращает первый истинный операнд (или последний, если истинных нет), and — первый ложный (или последний, если все истинны). Результат — операнд, а не обязательно bool.
Что такое ленивое (short-circuit) вычисление?
and не вычисляет правую часть, если левая ложна, а or — если левая истинна: ответ уже известен. На этом строятся защитные проверки вроде obj is not None and obj.price > 0.
Почему x == "paid" or "shipped" — ошибка?
Выражение разбирается как (x == "paid") or "shipped". Если первое сравнение ложно, or возвращает "shipped" — непустую строку, которая истинна. Условие выполняется всегда. Нужно x == "paid" or x == "shipped" (или проверка вхождения в коллекцию — раздел «Коллекции»).
Глубже
Почему True + True == 2 и как bool связан с int — в курсе «Python под капотом», тема «Целые числа».