Углубление в логические операторы Python
Конспект посвящён скрытым особенностям и неочевидным деталям логических операторов в Python
Truthy и falsy объекты
Falsy
— объекты, которые могут быть оценены как значение False
. К ним относятся следующие объекты:
- Значение
False
- Значение
None
- Числовые нули:
0
,0.0
,0j
,Decimal(0)
,Fraction(0, 1)
- Пустые последовательности и коллекции:
b''
,bytearray(b'')
,''
,[]
,()
,{}
,set()
,range(0)
Truthy
— объекты, которые могут быть оценены как значение True
. К ним относятся все объекты, не относящиеся к falsy
.
Чтобы представить такие объекты в булевом виде, можно использовать функцию bool()
.
Операторы and
и or
Операторы and
и or
не приводят свои результаты принудительно к значениям True
или False
, а возвращают один из своих операндов. Такой подход позволяет использовать эти операторы в более общих операциях, а не только в булевых.
Для начала посмотрим на оператор or
:
|
|
|
|
Как можно видеть, оператор or
оценивает каждый свой операнд как truthy
или falsy
объект, однако возвращает не значение True
или False
, а сам объект по определенному правилу — первый truthy
объект либо последний объект, если truthy
объекты в логическом выражении не найдены.
Подобным образом с помощью or
можно определять значение по умолчанию, к примеру:
|
|
Если пользователь ничего не передаст в функцию input()
, в переменную greet
попадёт строка "noname"
.
Перейдём к оператору and
:
|
|
|
|
Оператор and
возвращает первый falsy
объект либо последний объект, если falsy
объекты в логическом выражении не найдены.
Short-circuit evaluation
Операторы and
и or
укорачивают вычисление своих операндов (т.е. используют замыкания): правый операнд вычисляется лишь в том случае, если его значение необходимо для получения истинного значения в операциях and
или or
. Другими словами, замыкания в логических операциях используются для запуска второй части или последующих частей логического выражения только в том случае, если это актуально!
- Если левый операнд оператора
or
являетсяtruthy
объектом, то общим результатом логического выражения являетсяTrue
, независимо от значения правого операнда. - Если левый операнд оператора
and
являетсяfalsy
объектом, то общим результатом логического выражения являетсяFalse
, независимо от значения правого операнда.
Данный механизм называется вычислением по короткой схеме (short-circuit evaluation) и используется интерпретатором для оптимизации вычислений. Рассмотрим пример:
|
|
Левым операндом оператора or является truthy
объект, значит, для вычисления общего результата логического выражения нет необходимости вычислять правый операнд, то есть вызывать функцию f()
. Поскольку вызова функции не происходит, в выводе отсутствует строка bee
.
И наоборот, если заменить or
на and
, в выводе будут обе строки.
Приоритет логических операторов
Приоритет указан от наивысшего к наименьшему:
not
and
or
По отношению к другим операторам Python (за исключением оператора присваивания =
) логические операторы имеют самый низкий приоритет.
|
|
В этом коде сначала сравниваются значения переменных, затем применяется оператор not
.
Стоит упомянуть, что подобная запись будет вызывать исключение SyntaxError
:
|
|
Рассмотрим ещё один пример:
|
|
Согласно приоритету операторов в первую очередь вычисляются выражения 1 == 2
, 3 == 3
и 5 == 6
, в результате чего исходное выражение принимает вид not False or True and False
. Далее выполняется оператор not
, возвращая значение True
, после него — оператор and
, возвращая значение False
. Выражение принимает вид True or False
. Последним выполняется оператор or
, возвращая общий результат выражения — значение True
.
P.S. На самом деле после вычисления not 1 == 2
оператор or
сразу вернёт True
, не вычисляя правую часть.
Цепочки сравнений
Как известно, сравнивать объекты в Python можно в укороченной форме, например вместо a < b and b < c
писать a < b < c
Поскольку оператор and
реализует вычисление по короткой схеме, все сравнения, которые располагаются правее сравнения, вернувшего ложный результат, не выполняются, и их операнды не вычисляются:
|
|
Пояснение: выражение 5 < 1 < f()
эквивалентно выражению 5 < 1 and 1 < f()
. Сравнение 5 < 1
возвращает False
. В результате сравнение 1 < f()
не выполняется, и функция f()
не вызывается.
Тем не менее между сокращенным и расширенным вариантами записи цепочек сравнений существует важное отличие. В сокращенном выражении значение, стоящее по середине (между операторами сравнения), будет вычислено один раз (если его вообще нужно вычислять), а в развёрнутом выражении — два раза:
|
|
|
|
Помимо операторов сравнения, в цепочку операторов могут объединяться и другие операторы Python.
|
|
Данное выражение на самом деле эквивалентно выражению num in lst and lst == True
, которое, в свою очередь, эквивалентно выражению True and False
. Следовательно, результатом данной цепочки операторов является значение False
.
Рассмотрим ещё один пример:
|
|
|
|
Основной источник: https://habr.com/ru/articles/824170/
Доп. источники:
