Булева логика (алгебра логики, булева алгебра) — это раздел математики, который работает с высказываниями, принимающими ровно два значения: истина (True, 1) и ложь (False, 0). Из простых высказываний с помощью логических операций собирают сложные, а результат любого выражения тоже равен истине или лжи. На этой алгебре стоят условия if, циклы, фильтры запросов и вся цифровая схемотехника.
Содержание
Разберем базовые операции (И, ИЛИ, НЕ, XOR, импликация, эквивалентность), их таблицы истинности, законы де Моргана и то, как все это выглядит в коде. Отдельно разведем логическое И и битовое И — их часто путают, и эта путаница дает реальные баги.
Мини-словарь: что с чем не путать
Тема состоит из близких понятий, поэтому сначала короткий словарь.
- Высказывание — утверждение, про которое можно сказать, истинно оно или ложно («5 > 3»).
- Логическая операция — действие над высказываниями (И, ИЛИ, НЕ и т.д.).
- Таблица истинности — таблица, где для всех комбинаций входов выписан результат операции.
- Логический оператор (
and,or,not) — работает с истинностью выражения целиком. - Битовый оператор (
&,|,^,~) — работает отдельно с каждым битом числа.
Последние два — разные вещи, к ним вернемся в отдельном разделе.
Базовые логические операции
Пусть A и B — высказывания, каждое равно 0 (ложь) или 1 (истина). Основные операции:
| Операция | Названия | Обозначения в коде | Когда истинна |
|---|---|---|---|
| Конъюнкция | логическое И, AND | and, && |
оба операнда истинны |
| Дизъюнкция | логическое ИЛИ, OR | or, \|\| |
хотя бы один операнд истинен |
| Инверсия | отрицание, НЕ, NOT | not, ! |
исходное значение ложно |
| Исключающее ИЛИ | XOR, сложение по модулю 2 | ^ |
операнды различны |
| Импликация | следование | нет прямого оператора | ложна только когда из истины следует ложь |
| Эквивалентность | равнозначность | == для булевых |
операнды равны |
Импликацию и эквивалентность в языках чаще выражают через базовые операции, а не отдельным знаком: импликация A -> B равна (not A) or B, эквивалентность — обычному сравнению A == B.
Таблицы истинности
Таблица истинности перечисляет результат для всех комбинаций входов. Для двух переменных строк всегда четыре.
И, ИЛИ, XOR:
| A | B | A И B | A ИЛИ B | A XOR B |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 1 | 1 |
| 1 | 0 | 0 | 1 | 1 |
| 1 | 1 | 1 | 1 | 0 |
Импликация и эквивалентность:
| A | B | A -> B | A эквив. B |
|---|---|---|---|
| 0 | 0 | 1 | 1 |
| 0 | 1 | 1 | 0 |
| 1 | 0 | 0 | 0 |
| 1 | 1 | 1 | 1 |
Отрицание проще, для одной переменной:
| A | НЕ A |
|---|---|
| 0 | 1 |
| 1 | 0 |
Обратите внимание на импликацию: единственный ложный случай — когда условие A истинно, а следствие B ложно. Из ложной посылки следует что угодно, поэтому первые две строки дают истину.
Логические операторы в коде
В Python логические операторы — and, or, not. Проверим базовые случаи и один важный нюанс — что именно возвращают операторы.
print(True and False) # False
print(True or False) # True
print(not True) # False
# and/or возвращают ОПЕРАНД, а не всегда bool:
print("" and 5) # "" (первый ложный операнд)
print(0 or "hello") # hello (первый истинный операнд)
print(3 and 4) # 4 (оба истинны -> последний)
Вывод:
False
True
False
hello
4
Пустая строка выводится как пустая строка — это и есть значение "" and 5. Оператор and возвращает первый ложный операнд, а or — первый истинный; если таких нет, возвращается последний. Здесь работает понятие «истинность»: пустая строка, 0, None, пустой список считаются ложными, остальное — истинным.
Второе важное свойство — короткое замыкание (short-circuit): вычисление обрывается, как только результат ясен.
def side():
print("side called")
return True
print(False and side()) # side НЕ вызывается: и так False
print(True or side()) # side НЕ вызывается: и так True
Вывод:
False
True
Строки side called в выводе нет: до вызова side() дело не дошло. Это удобно для проверок вида if user is not None and user.is_active.
Логическое И (and) и битовое И (&) — не одно и то же
and смотрит на истинность всего выражения. & работает с каждым битом числа по отдельности. Сравним на числах 5 и 3:
print(bin(5), bin(3)) # 0b101 0b11
print(5 & 3) # 1 -> побитовое И: 0b101 & 0b011 = 0b001
print(5 | 3) # 7 -> побитовое ИЛИ: 0b111
print(5 ^ 3) # 6 -> побитовое XOR: 0b110
print(~5) # -6 -> инверсия битов
Вывод:
0b101 0b11
1
7
6
-6
Битовое И берет каждую пару битов: 1&1=1, 0&1=0, 1&1=1, что дает 0b001 = 1. А логическое 5 and 3 вернуло бы 3, потому что оба числа истинны.
Путаница операторов дает тихий баг. Классика — написать & вместо and между сравнениями:
x = 20
# намерение: (x > 0) and (x < 10) -> должно быть False
print(x > 0 & x < 10)
Вывод:
True
Результат неверный: ожидали False, получили True. Причина в приоритете: у & он выше, чем у сравнений, поэтому Python читает выражение как x > (0 & x) < 10, то есть как цепочку (x > 0) and (0 < 10), а это всегда истина. Исправление — использовать логический оператор и скобки:
x = 20
print((x > 0) and (x < 10)) # False - как и ожидалось
Вывод:
False
Правило простое: для условий (True/False) берите and, or, not; для работы с битами чисел — &, |, ^, ~.
Битовые операции и флаги
Битовые операторы удобны, когда несколько признаков упакованы в одно число. Каждый бит — отдельный флаг. Разберем права доступа:
READ, WRITE, EXEC = 0b001, 0b010, 0b100
perm = READ | WRITE # включаем два флага
print(bin(perm)) # 0b11
print(bool(perm & WRITE))# True - бит WRITE установлен
print(bool(perm & EXEC)) # False - бита EXEC нет
perm |= EXEC # добавить флаг
print(bin(perm)) # 0b111
perm &= ~WRITE # снять флаг
print(bin(perm)) # 0b101
Вывод:
0b11
True
False
0b111
0b101
Здесь | включает бит, & флаг проверяет его наличие, & ~флаг сбрасывает бит. XOR (^) переключает бит на противоположный. Такой прием встречается в правах файловой системы, настройках и сетевых масках.
Законы алгебры логики: де Моргана
Законы позволяют упрощать выражения. Самые ходовые в коде — законы де Моргана: отрицание конъюнкции равно дизъюнкции отрицаний, и наоборот.
- НЕ (A И B) = (НЕ A) ИЛИ (НЕ B)
- НЕ (A ИЛИ B) = (НЕ A) И (НЕ B)
Проверим первый закон полным перебором:
for a in (False, True):
for b in (False, True):
left = not (a and b)
right = (not a) or (not b)
print(a, b, left, right, left == right)
Вывод:
False False True True True
False True True True True
True False True True True
True True False False True
Последняя колонка везде True: обе части равны на всех входах, закон выполняется. На практике это помогает переписать not (x and y) в читаемое (not x) or (not y) и убрать лишние отрицания в условиях. Другие полезные тождества: коммутативность (a and b = b and a), а также a or (a and b) = a (закон поглощения).
Выводы
- Булева логика оперирует двумя значениями — истина и ложь; из простых высказываний операции собирают сложные, результат тоже булев.
- Базовый набор: И, ИЛИ, НЕ, XOR, импликация (
(not A) or B), эквивалентность (A == B); таблица истинности для двух входов — четыре строки. - Логические
and/or/notработают с истинностью выражения (и умеют короткое замыкание), битовые&/|/^/~— с отдельными битами числа; путать их нельзя. - У
&приоритет выше, чем у сравнений, — в условиях используйтеand/orи скобки. - Битовые операции удобны для флагов и масок; законы де Моргана упрощают отрицания в условиях.
Где применяется / связь с практикой
Булева логика — это фундамент условий, циклов и фильтров в любом коде, а также баз данных (WHERE a AND b), проверок форм и цифровой схемотехники. Без уверенного владения таблицами истинности и операторами сложно писать корректные ветвления и отлаживать «неожиданные» результаты условий.
Освойте тему на практике
Логика тесно связана с остальной прикладной математикой для разработчика — множествами, комбинаторикой, дискретными структурами. Собрать эту базу системно помогает курс Прикладная математика для разработчиков. Посмотреть формат и темы вживую можно на бесплатных открытых уроках Otus — там разбирают задачи и отвечают на вопросы.
FAQ
Чем импликация отличается от обычного «если»?
Импликация A -> B ложна ровно в одном случае: истинная посылка и ложное следствие. Из ложной посылки формально следует что угодно, поэтому строки с A=0 дают истину — это отличается от бытового «если».
Почему and иногда возвращает не True/False, а само значение?
В Python and возвращает первый ложный операнд, а or — первый истинный; если таких нет, возвращается последний вычисленный операнд. Поэтому 0 or "hello" дает строку hello, а не True.
XOR — это то же самое, что «не равно»?
Для булевых значений да: a ^ b истинно, когда операнды различны, что совпадает с a != b. Но ^ еще и битовый оператор для чисел, где он работает по каждому биту отдельно.



