Python: Результат логических выражений
Посмотрите на код ниже и попробуйте угадать, что будет напечатано на экран?
print(0 or 1)
Правильный ответ:
1
Оператор ИЛИ работает так, что его выполнение (слева направо) прерывается и возвращается результат первого аргумента, который можно преобразовать в True
, если такого аргумента нет, возвращается последний (правый).
Пример:
print(0 and 1)
0
Оператор И работает так, что его выполнение (слева направо) прерывается и возвращается результат первого аргумента, который можно преобразовать в 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')
Двойное отрицание
Вспомните операцию отрицания:
answer = True
print(not answer) # => False
При двойном отрицании итоговое значение равно начальному:
answer = True
print(not not answer) # => True
Но здесь дополнительно происходят преобразования типа. Поэтому результатом двойного отрицания всегда будет значение типа boolean.
Ошибка выбора
Представьте себе задачу, в которой нам нужно проверить, что значение равно либо одному, либо другому. Например переменная value
должна содержать одно из двух значений: first
или second
. Начинающие разработчики иногда записывают это выражение так:
value == ('first' or 'second')
В голове мы это себе примерно так и представляем, но языки работают по другому, поэтому такой код приведет к неверному результату. Как его правильно прочитать? Мы должны вспомнить приоритет выполнения операций. Первым делом вычисляется все что указано в скобках, то есть 'first' or 'second'
. Если выполнить этот код в репле, то вывод будет таким:
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
Упражнение не проходит проверку — что делать? 😶
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
- Обязательно приложите вывод тестов, без него практически невозможно понять что не так, даже если вы покажете свой код. Программисты плохо исполняют код в голове, но по полученной ошибке почти всегда понятно, куда смотреть.
В моей среде код работает, а здесь нет 🤨
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Мой код отличается от решения учителя 🤔
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Прочитал урок — ничего не понятно 🙄
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.