Python: Результат логических выражений
В этом уроке познакомимся с правилами преобразования аргумента и узнаем, как работать с составными выражениями и двойным отрицанием.
Правила преобразования
Оператор ИЛИ работает так, что его выполнение слева направо прерывается и возвращается результат первого аргумента, который можно преобразовать в True
. Если такого аргумента нет, возвращается последний — правый.
Посмотрите на пример:
print(0 or 1) ## 1
В данном случае, число 0
эквивалентно False
, а число 1
эквивалентно True
. Таким образом, оператор ИЛИ вернет 1
, так как это первый аргумент, который может быть преобразован в True
.
Возьмем пример посложнее:
print(0 or False or '' or [] or 42 or "Hello") ## 42
В данном случае:
- Число
0
эквивалентноFalse
- Значение
False
уже являетсяFalse
- Пустая строка (
''
) эквивалентнаFalse
- Пустой список (
[]
) эквивалентенFalse
- Число
42
эквивалентноTrue
- Строка
"Hello"
также эквивалентнаTrue
Оператор ИЛИ будет проверять значения слева направо, и возвращает первый аргумент, который может быть преобразован в True
. В данном примере это число 42
.
Пример с оператором И:
print(0 and 1) ## 0
Оператор И работает так, что его выполнение слева направо прерывается и возвращается результат первого аргумента, который можно преобразовать в False
. Если такого аргумента нет, возвращается последний — правый.
print(42 and "Hello" and [] and 0) ## []
В данном случае:
- Число
42
эквивалентноTrue
- Строка
"Hello"
эквивалентнаTrue
- Пустой список (
[]
) эквивалентенFalse
- Число
0
эквивалентноFalse
Оператор И будет проверять значения слева направо и возвращать первый аргумент, который может быть преобразован в False
. В данном примере это пустой список ([]
).
В Python есть два правила преобразования:
0
,0.0
,''
иNone
приводятся кFalse
. Эти значения называют falsy. Сюда входят еще другие типы данных, которые мы будем изучать на Хекслете- Все остальное приводится к
True
Этими правилами пользуются в разработке, например, чтобы определить значение по умолчанию:
value = name or ''
# Примеры
234 or '' # 234
'hexlet' or '' # 'hexlet'
None or '' # ''
Если name
примет одно из falsy-значений, переменной value
будет присвоена пустая строка. В этом случае в последующем коде мы сможем работать с value
как со строкой.
Но здесь есть потенциальный баг. Если name
содержит falsy значение, а переменной value
можно присвоить значения типа 0
, False
, None
, то код выше заработает неверно:
# Значение на самом деле есть,
# но оно Falsy, поэтому не выбирается на условии OR
False or '' # ''
0 or '' # ''
None or '' # ''
Составные выражения
Если соединить логические выражения между собой, можно получать довольно интересные способы решения задач с кодом.
Допустим, нам нужно реализовать код, в котором в переменную записывается:
- Строка
yes
, если число четное - Строка
no
, если нечетное
Это можно сделать, если использовать знания, полученные выше:
# число четное
result = 10 % 2 == 0 and 'yes' or 'no' # 'yes'
# или сразу печатаем на экран
print(10 % 2 == 0 and 'yes' or 'no') # => 'yes'
# число нечетное
print(11 % 2 == 0 and 'yes' or 'no') # => 'no'
Эти выражения работают согласно порядку и приоритетам. Приоритет присваивания самый низкий, поэтому оно происходит в конце. Приоритет сравнения ==
выше, чем приоритет логических операторов and
и or
, поэтому сравнение происходит раньше. Дальше код выполняется слева направо, так как приоритет and
выше, чем приоритет or
. Рассмотрим по шагам:
# Для четного
# 1 шаг
10 % 2 == 0 # True
# 2 шаг
True and 'yes' # Результат — истина
# Проверка на or выполняется, но правая часть не исполняется, так как сразу возвращается 'yes'
# Для нечетного
# 1 шаг
11 % 2 == 0 # False
# 2 шаг
False and 'yes' # Результат — ложь, проверяем дальше
# 3 шаг
False or 'no' # Выбирается и возвращается 'no'
Такую же схему можно использовать с любым выражением в начале:
print(somefunc() and 'yes' or 'no')
Можете проверить себя и поэкспериментировать с кодом в Replit.
Двойное отрицание
Напомним, как выглядит операция отрицания:
answer = True
print(not answer) # => False
При двойном отрицании итоговое значение равно начальному:
answer = True
print(not not answer) # => True
Оператор not
всегда возвращает булевое значение, независимо от типа переданного аргумента, а не заменяет значение на противоположное. Поэтому двойное отрицание тоже вернет булевое True/False.
answer = 'python'
print(not answer) # => False
print(not not answer) # => True
Ошибка выбора
Представьте, что нам нужно проверить — значение равно одному или другому. Например, переменная value
должна содержать одно из двух значений: first
или second
. Начинающие разработчики иногда записывают это выражение так:
value == ('first' or 'second')
Однако такой код приведет к неверному результату. Необходимо вспомнить приоритет выполнения операций. Первым делом вычисляется все, что указано в скобках — 'first' or 'second'
. Если выполнить этот код в Replit, то вывод будет таким:
python
Python 3.8.2 (default, Apr 12 2020, 15:53:37)
>>> 'first' or 'second'
'first'
>>>
Теперь заменим исходное выражение на частично вычисленное:
value == 'first'
Совсем не то, что мы ожидали. А теперь вернемся к началу и напишем проверку правильно:
# Скобки ставить не обязательно,
# потому что приоритет == выше чем приоритет or
value == 'first' or value == 'second'
Задание
Реализуйте функцию string_or_not()
, которая проверяет является ли переданный параметр строкой. Если да, то возвращается 'yes'
иначе 'no'
string_or_not('Hexlet') # 'yes'
string_or_not(10) # 'no'
string_or_not('') # 'yes'
string_or_not(False) # 'no'
Проверить то, является ли переданный параметр строкой, можно при помощи функции isinstance():
isinstance(3, str) # False
isinstance('Hexlet', str) # True
Поэкспериментируйте с кодом в интерактивном репле https://replit.com/@hexlet/python-basics-logical-expressions
Упражнение не проходит проверку — что делать? 😶
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
- Обязательно приложите вывод тестов, без него практически невозможно понять что не так, даже если вы покажете свой код. Программисты плохо исполняют код в голове, но по полученной ошибке почти всегда понятно, куда смотреть.
В моей среде код работает, а здесь нет 🤨
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Мой код отличается от решения учителя 🤔
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Прочитал урок — ничего не понятно 🙄
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.