Булевое выражение Python и
В python, если вы пишете что-то вроде
foo==bar and spam or eggs
Кажется, что python возвращает спам, если логическое утверждение истинно, а яйца - в противном случае. Может ли кто-нибудь объяснить это поведение? Почему выражение не оценивается как один длинный логический?
Изменить: В частности, я пытаюсь выяснить механизм, по которому "спам" или "яйца" возвращаются в результате выражения.
Ответы
Ответ 1
Операторы and
и or
являются короткозамкнутыми, что означает, что если результат выражения может быть выведен из оценки только первого операнда, второй не оценивается. Например, если выражение a or b
и a
равно true, то не имеет значения, что такое b
, результат выражения true, поэтому b
не оценивается. Они фактически работают следующим образом:
-
a and b
: Если a является ложным, b не оценивается и возвращается a, в противном случае возвращается b.
-
a or b
: Если a является правдой, b не оценивается и возвращается a, в противном случае возвращается b.
Ложные и правдивые относятся к значениям, которые вычисляются в false или true в булевом контексте.
Однако эта и/или идиома была полезной в те времена, когда лучшей альтернативы не было, но теперь есть лучший способ:
spam if foo==bar else eggs
Проблема с и/или идиомой (кроме того, что она запутывает новичков) заключается в том, что она дает неверный результат, если условие истинно, но спам оценивает значение false (например, пустую строку). По этой причине вам следует избегать этого.
Ответ 2
Так работают булевы операторы Python.
Из документация (последний абзац объясняет, почему это хорошая идея, что операторы работают так, как они это делают):
В контексте булевых операций, а также когда выражения используются операторы потока управления, следующие значения интерпретируются как ложные: False
, None
, числовое значение нуля всех типов и пустых строк и контейнеры (включая строки, кортежи, списки, словари, наборы и frozensets). Все остальные значения интерпретируется как истина. (См. __nonzero__()
специальный способ для изменения этого.)
Оператор not
дает True
, если его аргумент false, False
в противном случае.
Выражение x and y
сначала оценивает x
; если x
является ложным, его значение равно вернулся; в противном случае y
оценивается и полученное значение возвращается.
Выражение x or y
сначала оценивает x
; если x
истинно, его значение равно вернулся; в противном случае y вычисляется и полученное значение возвращается.
(Обратите внимание, что ни and
, ни or
не ограничивают значение и тип, которые они возвращают False
и True
, а скорее верните последний оцененный аргумент. Это иногда полезно, например, если s
является строка, которая должна быть заменена значение по умолчанию, если оно пустое, выражение s or 'foo'
дает желаемое значение. Потому что not
должен все равно придумайте значение, это не позаботьтесь о возврате значения того же введите в качестве своего аргумента, например, not 'foo'
дает False
, а не ''
.)
Ответ 3
Причина в том, что Python оценивает логическое выражение, используя фактические значения задействованных переменных, вместо того, чтобы ограничивать их значениями True
и False
. Следующие значения считаются ложными:
-
None
-
False
- 0 любого числового типа
- пустая последовательность или набор (
''
, ()
, []
, {}
)
- определяемые пользователем типы с помощью метода
__nonzero__()
или __len__()
, который возвращает 0 или False
Дополнительную информацию см. в разделе Проверка прав собственности в документации Python. В частности:
Операции и встроенные функции, имеющие логический результат, всегда возвращают 0
или False
для false и 1
или True
для true, если не указано иное. (Важное исключение: логические операции or
и and
всегда возвращают один из их операндов.)
Ответ 4
Попробуйте использовать круглые скобки, чтобы сделать выражение не двусмысленным. Так оно и есть, вы получаете:
(foo == bar and spam) or eggs