Сравнения и логика

Теория

Почти каждое решение в программе — это вопрос с ответом «да» или «нет»: товар в наличии? заказ оплачен? сумма больше порога? Операторы сравнения (==, !=, <, >, <=, >=) отвечают на такие вопросы и возвращают 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, его можно сохранить в переменную:

python
stock = 12
price = 1499
budget = 5000
in_stock = stock > 0
affordable = price <= budget
print(in_stock, affordable)

Результат:

вывод
True True

Шаг 2. Сравниваем строки

Строки сравниваются посимвольно и с учётом регистра:

python
status = "Paid"
print(status == "paid", status.lower() == "paid")
print("10" < "9")

Результат:

вывод
False True
True

"10" < "9" — потому что сравниваются символы: "1" меньше "9". Числа, пришедшие строками, перед сравнением приводят к числам.

Шаг 3. Проверяем диапазон цепочкой

Python позволяет писать сравнения цепочкой, как в математике:

python
print(1000 <= price <= 5000)

Результат:

вывод
True

Это то же самое, что 1000 <= price and price <= 5000.

Шаг 4. Объединяем условия

Кнопка «Купить» доступна, если товар активен и есть на складе и по карману:

python
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. Без скобок смысл может поменяться:

python
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() показывает, как значение поведёт себя в условии:

python
print(bool(0), bool(12), bool(""), bool("0"), bool(None))

Результат:

вывод
False True False True False

Шаг 7. Пользуемся ленивым вычислением

and не вычисляет правую часть, если левая ложна. Это защищает от ошибки, когда остаток неизвестен:

python
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 под капотом», тема «Целые числа».

Ошибка в тексте

Сообщить об ошибке могут зарегистрированные пользователи — так в сообщениях меньше спама.

Войти, чтобы сообщить