Булевое выражение 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