Логическое выражение Python и или - PullRequest
16 голосов
/ 06 июля 2010

В python, если вы пишете что-то вроде

foo==bar and spam or eggs

, python возвращает спам, если логическое утверждение истинно, и возвращает в противном случае.Может ли кто-нибудь объяснить это поведение?Почему выражение не оценивается как одно длинное логическое значение?

Редактировать: В частности, я пытаюсь выяснить механизм, почему в результате выражения возвращается «спам» или «яйца».

Ответы [ 4 ]

18 голосов
/ 06 июля 2010

Операторы and и or имеют короткое замыкание, что означает, что если результат выражения может быть выведен из вычисления только первого операнда, второй не оценивается. Например, если у вас есть выражение a or b и a оценивается как true, тогда не имеет значения, что такое b, результат выражения равен true, поэтому b не оценивается. Они на самом деле работают следующим образом:

  • a and b: если a равно false, b не оценивается, и возвращается a, в противном случае возвращается b.
  • a or b: если a верно, b не вычисляется и возвращается, в противном случае возвращается b.

Ложь и истина относятся к значениям, которые оцениваются как ложные или истинные в логическом контексте.

Однако эта и / или идиома была полезна в те времена, когда не было лучшей альтернативы, но теперь есть лучший способ:

spam if foo==bar else eggs

Проблема с и / или идиомой (кроме того, что она вводит в заблуждение новичков) состоит в том, что она дает неверный результат, если условие выполняется, но спам оценивается как ложное значение (например, пустая строка). По этой причине вам следует избегать этого.

5 голосов
/ 06 июля 2010

Вот как работают булевы операторы Python.

Из документации (последний абзац объясняет, почему операторы работают так, как они работают):

В контексте логических операций, а также когда выражения используются в выражениях потока управления, следующие значения интерпретируются как ложные: False, None, числовой ноль всех типов и пустые строкии контейнеры (включая строки, кортежи, списки, словари, наборы и фрозенсеты).Все остальные значения интерпретируются как истина.(См. Специальный метод __nonzero__(), чтобы узнать, как это изменить.)

Оператор not возвращает True, если его аргумент равен false, False в противном случае.

Выражениеx and y первая оценка x;если x равно false, возвращается его значение;в противном случае y вычисляется и возвращается полученное значение.

Выражение x or y сначала оценивает x;если x истинно, возвращается его значение;в противном случае вычисляется y и возвращается результирующее значение.

(Обратите внимание, что ни and, ни or не ограничивают возвращаемое значение и тип, равные False и True, но скорее возвращают последнееоцененный аргумент. Это иногда полезно, например, если s является строкой, которая должна быть заменена значением по умолчанию, если оно пустое, выражение s or 'foo' возвращает желаемое значение. Поскольку not все равно должен придумывать значениеон не возвращает значение того же типа, что и его аргумент, например, not 'foo' дает False, а не ''.)

3 голосов
/ 06 июля 2010

Причина в том, что Python оценивает логическое выражение, используя фактические значения задействованных переменных, вместо того, чтобы ограничивать их значениями True и False.Следующие значения считаются ложными:

  • None
  • False
  • 0 любого числового типа
  • пустая последовательность илиset ('', (), [], {})
  • пользовательских типов с методом __nonzero__() или __len__(), который возвращает 0 или False

Дополнительную информацию смотрите в разделе Проверка истинности в документации по Python.В частности:

Операции и встроенные функции, которые имеют логический результат, всегда возвращают 0 или False для false и 1 или True для true, если не указано иное.(Важное исключение: логические операции or и and всегда возвращают один из своих операндов.)

2 голосов
/ 06 июля 2010

Попробуйте использовать скобки, чтобы сделать выражение не двусмысленным.Так оно и есть:

(foo == bar and spam) or eggs
...