Python & AI Tutorials Logo
Программирование Python

9. Объединение условий с булевой логикой

В главе 7 мы изучили булевы значения и простые условия с использованием операторов сравнения. В главе 8 мы использовали эти условия, чтобы принимать решения с помощью операторов if. Но в реальных программах часто нужно проверять несколько условий одновременно. Следует ли предоставлять доступ, если у пользователя правильный пароль и он вошёл в систему? Нужно ли показывать предупреждение, если температура слишком высокая или слишком низкая? Следует ли продолжать, если файл не пустой?

Python предоставляет три логических оператора (logical operators), которые позволяют объединять и изменять булевы значения: and, or и not. Эти операторы — строительные блоки для выражения сложной логики принятия решений в ваших программах.

9.1) Логические операторы and, or и not

Три логических оператора работают с булевыми значениями (или значениями, которые можно трактовать как булевы), чтобы получать новые булевы результаты.

9.1.1) Оператор and

Оператор and возвращает True только тогда, когда оба операнда истинны. Если хотя бы один операнд ложен, всё выражение ложно.

python
# Оба условия должны быть истинными
age = 25
has_license = True
 
can_rent_car = age >= 21 and has_license
print(can_rent_car)  # Output: True
 
# Если хотя бы одно условие ложно, результат — False
age = 18
can_rent_car = age >= 21 and has_license
print(can_rent_car)  # Output: False

Думайте об and как о строгом охраннике: все условия должны пройти, чтобы общая проверка считалась успешной.

Таблица истинности для and:

Левый операндПравый операндРезультат
TrueTrueTrue
TrueFalseFalse
FalseTrueFalse
FalseFalseFalse

9.1.2) Оператор or

Оператор or возвращает True, когда хотя бы один операнд истинный. Он возвращает False только тогда, когда оба операнда ложны.

python
# Хотя бы одно условие должно быть истинным
is_weekend = True
is_holiday = False
 
can_sleep_in = is_weekend or is_holiday
print(can_sleep_in)  # Output: True
 
# Оба условия ложны
is_weekend = False
is_holiday = False
can_sleep_in = is_weekend or is_holiday
print(can_sleep_in)  # Output: False

Думайте об or как о снисходительном охраннике: достаточно выполнить одно условие, чтобы пройти.

Таблица истинности для or:

Левый операндПравый операндРезультат
TrueTrueTrue
TrueFalseTrue
FalseTrueTrue
FalseFalseFalse

Вот практический пример для системы определения права на скидку:

python
# Клиент получает скидку, если он студент ИЛИ пенсионер
age = 68
is_student = False
 
gets_discount = is_student or age >= 65
print(f"Eligible for discount: {gets_discount}")  # Output: Eligible for discount: True
 
# Другой клиент
age = 30
is_student = False
gets_discount = is_student or age >= 65
print(f"Eligible for discount: {gets_discount}")  # Output: Eligible for discount: False

Первый клиент подходит, потому что он соответствует одному из критериев (пенсионер), даже несмотря на то, что он не студент.

9.1.3) Оператор not

Оператор not — это унарный оператор (unary operator) (он работает с одним операндом), который обращает булево значение. Он превращает True в False, а False — в True.

python
is_raining = False
is_sunny = not is_raining
print(is_sunny)  # Output: True
 
is_raining = True
is_sunny = not is_raining
print(is_sunny)  # Output: False

Таблица истинности для not:

ОперандРезультат
TrueFalse
FalseTrue

Оператор not особенно полезен, когда вы хотите проверить противоположное условие:

python
# Проверяем, что файл НЕ пустой
file_size = 0
is_empty = file_size == 0
is_not_empty = not is_empty
print(f"File has content: {is_not_empty}")  # Output: File has content: False
 
# Проверяем, что пользователь НЕ вошёл в систему
is_logged_in = False
needs_login_prompt = not is_logged_in
print(f"Show login prompt: {needs_login_prompt}")  # Output: Show login prompt: True

9.1.4) Комбинирование нескольких логических операторов

Вы можете комбинировать несколько логических операторов в одном выражении, чтобы строить более сложные условия:

python
# Интернет-магазин: бесплатная доставка, если сумма заказа больше $50 ИЛИ клиент — премиум-участник
# И товары есть в наличии
order_total = 45.00
is_premium = True
in_stock = True
 
gets_free_shipping = (order_total >= 50 or is_premium) and in_stock
print(f"Free shipping: {gets_free_shipping}")  # Output: Free shipping: True

Давайте проследим выполнение этого выражения:

  1. order_total >= 50 вычисляется как False (45.00 не >= 50)
  2. is_premium равно True
  3. False or True вычисляется как True
  4. in_stock равно True
  5. True and True вычисляется как True

Вот ещё один пример с контролем доступа:

python
# Пользователь может получить доступ к панели администратора, если он администратор
# И (он во внутренней сети ИЛИ использует VPN)
is_admin = True
on_internal_network = False
using_vpn = True
 
can_access_admin = is_admin and (on_internal_network or using_vpn)
print(f"Can access admin panel: {can_access_admin}")  # Output: Can access admin panel: True

Обратите внимание на скобки вокруг (on_internal_network or using_vpn). Они важны, потому что управляют порядком вычисления — так же, как скобки в арифметических выражениях.

9.2) Приоритет операторов в булевых выражениях (порядок Not, And, Or)

Когда вы комбинируете несколько логических операторов без скобок, Python следует определённым правилам приоритета, чтобы определить порядок вычисления. Понимание этих правил помогает писать корректные условия и избегать скрытых ошибок.

9.2.1) Иерархия приоритета

Python вычисляет логические операторы в таком порядке (от наивысшего к наинизшему приоритету):

  1. not (наивысший приоритет)
  2. and (средний приоритет)
  3. or (наинизший приоритет)

Это означает, что сначала вычисляется not, затем and, и в конце or.

python
# Без скобок порядок определяется приоритетом
result = True or False and False
print(result)  # Output: True
 
# Как Python вычисляет это:
# Шаг 1: False and False → False (у and приоритет выше, чем у or)
# Шаг 2: True or False → True

Давайте разберём это пошагово на более подробном примере:

python
is_weekend = False
is_holiday = True
has_work = True
 
# Выражение: not has_work or is_weekend and is_holiday
free_time = not has_work or is_weekend and is_holiday
 
# Порядок вычисления:
# Шаг 1: not has_work → not True → False
# Шаг 2: is_weekend and is_holiday → False and True → False
# Шаг 3: False or False → False
print(f"Has free time: {free_time}")  # Output: Has free time: False

9.2.2) Использование скобок для ясности

Даже если вы понимаете правила приоритета, использование скобок делает код понятнее и предотвращает ошибки. Скобки переопределяют стандартный приоритет и явно показывают ваши намерения.

python
# Неоднозначно без скобок
result = True or False and False
print(result)  # Output: True
 
# Понятно со скобками — что мы на самом деле имели в виду?
result = (True or False) and False
print(result)  # Output: False
 
result = True or (False and False)
print(result)  # Output: True

Эти два выражения дают разные результаты! Скобки полностью меняют смысл.

9.2.3) Операторы сравнения и логические операторы вместе

Операторы сравнения (такие как <, >, ==, !=) имеют более высокий приоритет, чем логические операторы. Это означает, что сравнения вычисляются до логических операций.

python
age = 25
income = 50000
 
# Вокруг сравнений не нужны скобки
eligible = age >= 18 and income >= 30000
print(f"Eligible for loan: {eligible}")  # Output: Eligible for loan: True
 
# Python вычисляет это так:
# Шаг 1: age >= 18 → True
# Шаг 2: income >= 30000 → True
# Шаг 3: True and True → True

9.3) Вычисление с коротким замыканием

Python использует вычисление с коротким замыканием (short-circuit evaluation) при вычислении булевых выражений с and и or. Это означает, что Python прекращает вычисление, как только узнаёт итоговый результат, потенциально пропуская вычисление последующих операндов. Такое поведение — и оптимизация производительности, и полезный приём программирования.

9.3.1) Как происходит короткое замыкание у and

С оператором and, если левый операнд равен False, Python знает, что всё выражение должно быть False (потому что оба операнда должны быть истинными, чтобы and вернул True). Поэтому Python вообще не вычисляет правый операнд.

python
# Простая демонстрация
x = 5
result = x < 3 and x > 10
print(result)  # Output: False
 
# Как Python вычисляет:
# Шаг 1: x < 3 → 5 < 3 → False
# Шаг 2: Так как левая часть False, не вычислять x > 10
# Шаг 3: Вернуть False

Вот практический пример, показывающий, почему вычисление с коротким замыканием важно:

python
# Проверяем делимость числа — избегаем деления на ноль
numerator = 100
denominator = 0
 
# Это безопасно благодаря вычислению с коротким замыканием
# Если denominator равен 0, деление никогда не произойдёт
is_divisible = denominator != 0 and numerator % denominator == 0
print(f"Is divisible: {is_divisible}")  # Output: Is divisible: False
 
# Без короткого замыкания это вызвало бы ошибку:
# denominator = 0
# result = numerator % denominator  # ZeroDivisionError!

Выражение denominator != 0 вычисляется как False, поэтому Python никогда не вычисляет numerator % denominator, что вызвало бы ошибку деления на ноль.

Посмотрим ещё один пример со строковыми операциями:

python
# Безопасно проверяем свойства строки
text = ""
 
# Проверяем, что text не пустой И первый символ — заглавный
# Это безопасно, потому что если text пустой, мы не пытаемся обращаться к text[0]
has_uppercase_start = len(text) > 0 and text[0].isupper()
print(f"Starts with uppercase: {has_uppercase_start}")  # Output: Starts with uppercase: False
 
# Если попытаться сделать это без проверки длины:
# text = ""
# result = text[0].isupper()  # IndexError: string index out of range

9.3.2) Как происходит короткое замыкание у or

С оператором or, если левый операнд равен True, Python знает, что всё выражение должно быть True (потому что достаточно, чтобы хотя бы один операнд был истинным). Поэтому Python не вычисляет правый операнд.

python
# Простая демонстрация
x = 15
result = x > 10 or x < 5
print(result)  # Output: True
 
# Как Python вычисляет:
# Шаг 1: x > 10 → 15 > 10 → True
# Шаг 2: Так как левая часть True, не вычислять x < 5
# Шаг 3: Вернуть True

9.3.3) Практические применения вычисления с коротким замыканием

Избежание ошибок:

python
# Безопасно обращаемся к элементам списка
numbers = [1, 2, 3]
index = 5
 
# Проверяем, что index корректный, прежде чем обращаться
is_valid = index < len(numbers) and numbers[index] > 0
print(f"Valid and positive: {is_valid}")  # Output: Valid and positive: False
 
# Без короткого замыкания это бы упало:
# is_valid = numbers[index] > 0  # IndexError!

Эффективная проверка нескольких условий:

python
# Валидация формы — остановка на первой ошибке
email = "user@example.com"
password = "pass"
age = 25
 
# Проверяем каждое требование в порядке, где чаще всего происходит сбой
valid_form = (
    len(email) > 0 and              # Быстрая проверка
    "@" in email and                # Быстрая проверка
    len(password) >= 8 and          # Быстрая проверка
    age >= 18                       # Быстрая проверка
)
print(f"Form valid: {valid_form}")  # Output: Form valid: False
# Останавливается на проверке длины пароля, не вычисляет age

Нет

Да

Да

Нет

Выражение and

Левая сторона True?

Вернуть False
Пропустить правую сторону

Вычислить правую сторону

Вернуть результат правой стороны

Выражение or

Левая сторона True?

Вернуть True
Пропустить правую сторону

Вычислить правую сторону

Вернуть результат правой стороны

9.4) Что возвращают операторы and и or с небулевыми операндами и распространённые ловушки булевых выражений

До сих пор мы видели, как and, or и not работают с булевыми значениями. Но у логических операторов Python есть интересное поведение: они могут работать с любыми значениями, а не только с True и False. Понимание этого поведения помогает писать более лаконичный код и избегать распространённых ошибок.

9.4.1) Понимание truthy и falsy (повторение)

Как мы узнали в главе 7, Python трактует многие небулевы значения как «truthy» или «falsy» в булевых контекстах:

Falsy значения (трактуются как False):

  • False
  • None
  • 0 (ноль любого числового типа)
  • "" (пустая строка)
  • [] (пустой список)
  • {} (пустой словарь)
  • () (пустой кортеж)

Truthy значения (трактуются как True):

  • True
  • Любое ненулевое число
  • Любая непустая строка
  • Любая непустая коллекция
python
# Демонстрация truthy
if "hello":
    print("Non-empty strings are truthy")  # Output: Non-empty strings are truthy
 
if 0:
    print("This won't print")  # Ноль — falsy
else:
    print("Zero is falsy")  # Output: Zero is falsy
 
if [1, 2, 3]:
    print("Non-empty lists are truthy")  # Output: Non-empty lists are truthy

9.4.2) Что на самом деле возвращает and

Оператор and не всегда возвращает True или False. Вместо этого он возвращает один из своих операндов:

  • Если левый операнд falsy, and возвращает левый операнд (не вычисляя правый)
  • Если левый операнд truthy, and возвращает правый операнд
python
# and возвращает первое falsy значение или последнее значение, если все truthy
result = 5 and 10
print(result)  # Output: 10
 
result = 0 and 10
print(result)  # Output: 0
 
result = "hello" and "world"
print(result)  # Output: world
 
result = "" and "world"
print(result)  # Output: (empty string)
 
result = None and "world"
print(result)  # Output: None

Давайте проследим эти примеры:

python
# Пример 1: Оба truthy
result = 5 and 10
# Шаг 1: 5 — truthy, поэтому вычисляем правую сторону
# Шаг 2: Возвращаем значение правой стороны: 10
print(result)  # Output: 10
 
# Пример 2: Левая сторона — falsy
result = 0 and 10
# Шаг 1: 0 — falsy, поэтому сразу возвращаем его
# Шаг 2: Не вычисляем правую сторону
print(result)  # Output: 0
 
# Пример 3: Обе строки truthy
result = "hello" and "world"
# Шаг 1: "hello" — truthy, поэтому вычисляем правую сторону
# Шаг 2: Возвращаем значение правой стороны: "world"
print(result)  # Output: world

9.4.3) Что на самом деле возвращает or

Аналогично, оператор or возвращает один из своих операндов:

  • Если левый операнд truthy, or возвращает левый операнд (не вычисляя правый)
  • Если левый операнд falsy, or возвращает правый операнд
python
# or возвращает первое truthy значение или последнее значение, если все falsy
result = 5 or 10
print(result)  # Output: 5
 
result = 0 or 10
print(result)  # Output: 10
 
result = "" or "default"
print(result)  # Output: default
 
result = "hello" or "world"
print(result)  # Output: hello
 
result = None or 0
print(result)  # Output: 0

Давайте проследим эти примеры:

python
# Пример 1: Левая сторона — truthy
result = 5 or 10
# Шаг 1: 5 — truthy, поэтому сразу возвращаем его
# Шаг 2: Не вычисляем правую сторону
print(result)  # Output: 5
 
# Пример 2: Левая сторона — falsy
result = 0 or 10
# Шаг 1: 0 — falsy, поэтому вычисляем правую сторону
# Шаг 2: Возвращаем значение правой стороны: 10
print(result)  # Output: 10
 
# Пример 3: Обе стороны falsy
result = None or 0
# Шаг 1: None — falsy, поэтому вычисляем правую сторону
# Шаг 2: Возвращаем значение правой стороны: 0 (хотя оно тоже falsy)
print(result)  # Output: 0

9.4.4) Практические применения or для значений по умолчанию

Один распространённый шаблон — использовать or для задания значений по умолчанию:

python
# Пользовательские предпочтения со значениями по умолчанию
user_theme = ""  # Пользователь не задал тему
theme = user_theme or "light"
print(f"Theme: {theme}")  # Output: Theme: light
 
user_theme = "dark"
theme = user_theme or "light"
print(f"Theme: {theme}")  # Output: Theme: dark
 
# Значения конфигурации
max_retries = None  # Не настроено
retries = max_retries or 3
print(f"Retries: {retries}")  # Output: Retries: 3
 
max_retries = 5
retries = max_retries or 3
print(f"Retries: {retries}")  # Output: Retries: 5

Этот шаблон работает, потому что если левая часть falsy (пустая строка, None, 0 и т. д.), or возвращает правую часть (значение по умолчанию).

and

or

Да

Нет

Да

Нет

Логический оператор с небулевым значением

Тип оператора

Левая сторона falsy?

Левая сторона truthy?

Вернуть значение левой стороны

Вернуть значение правой стороны

Вернуть значение левой стороны

Вернуть значение правой стороны

9.4.12) Сводка того, что возвращают операторы

Вот исчерпывающая сводка того, что возвращает каждый логический оператор:

Оператор and:

  • Возвращает первый falsy операнд
  • Если все операнды truthy, возвращает последний операнд
  • Использует вычисление с коротким замыканием (останавливается на первом falsy значении)

Оператор or:

  • Возвращает первый truthy операнд
  • Если все операнды falsy, возвращает последний операнд
  • Использует вычисление с коротким замыканием (останавливается на первом truthy значении)

Оператор not:

  • Всегда возвращает булево значение (True или False)
  • not преобразует операнд в булево значение, затем инвертирует его
python
# Демонстрация всех трёх операторов
print(5 and 10)           # Output: 10 (both truthy, return last)
print(0 and 10)           # Output: 0 (first falsy, return it)
print(5 or 10)            # Output: 5 (first truthy, return it)
print(0 or 10)            # Output: 10 (first falsy, evaluate second)
print(not 5)              # Output: False (5 is truthy, not returns boolean)
print(not 0)              # Output: True (0 is falsy, not returns boolean)
print(not "")             # Output: True (empty string is falsy)
print(not "hello")        # Output: False (non-empty string is truthy)

Понимание этих особенностей помогает писать более лаконичный и Pythonic-код, но всегда ставьте ясность на первое место. Если использование этих возможностей делает ваш код труднее для понимания, лучше писать явно.


В этой главе мы изучили, как объединять простые условия в сложную булеву логику с помощью операторов and, or и not в Python. Мы узнали о приоритете операторов, вычислении с коротким замыканием и неожиданном поведении логических операторов с небулевыми значениями. Мы также рассмотрели распространённые ловушки и лучшие практики для написания понятных, корректных булевых выражений.

Эти инструменты позволяют выражать сложную логику принятия решений в ваших программах. В сочетании с операторами if из главы 8 вы теперь можете обрабатывать практически любую условную логику, которая требуется вашим программам. В следующей главе мы рассмотрим условные выражения, которые дают компактный способ выбирать между двумя значениями на основе условия.


© 2025. Primesoft Co., Ltd.
support@primesoft.ai