Вещи Python, которые не являются ни истинными, ни ложными

Я только что нашел это:

a = (None,)
print (a is True)
print (a is False)
print (a == True)
print (a == False)
print (a == None)
print (a is None)
if a : print "hello"
if not a : print "goodbye"

который производит:

False
False
False
False
False
False
hello

Таким образом, ни один, ни равный True или False, но действует как истина в выражении if.

Почему?

Обновление:

На самом деле, я только что понял, что это не так неясно, как я думал. Я получаю тот же результат для a = 2 (хотя и не для a = 0 или = 1, которые считаются равными False и True соответственно)

Ответ 1

a является одночленным кортежем, который оценивается как True. is проверьте идентификатор объекта, поэтому вы получите False во всех этих тесте. == проверьте равенство объектов, поэтому вы снова получите False.

in if Оператор a __bool__ (или __nonzero__), используемый для оценки объекта, для непустого кортежа он должен возвращать True, поэтому вы получаете True. надеюсь, что ответит на ваш вопрос.

изменить: причина True и False равна 1 и 0 соответственно потому, что тип bool реализован как подкласс типа int.

Ответ 2

Я нахожу почти все объяснения здесь бесполезными, так что вот еще одна попытка:

Путаница здесь основана на том, что тестирование с помощью "is", "==" и "if" - это три разные вещи.

  • "is" проверяет идентичность, то есть, если это тот же объект. В этом случае это не так.
  • "==" проверяет значение равенства, и, очевидно, единственными встроенными объектами со значениями True и False являются объект True и False (за исключением чисел 0 и 1 любого числового типа).

И вот важная часть:

  • 'if' проверяет логические значения. Это означает, что любое выражение, которое вы ему даете, будет преобразовано в True или False. Вы можете сделать то же самое с bool(). И bool ((None)) вернет True. Вещи, которые будут оценивать False, перечислены в документах (связанных с другими здесь).

Теперь, может быть, это еще более ясно в моей голове, но, по крайней мере, я попробовал.:)

Ответ 3

Вещи в python не должны быть одним из True или False.

Когда они используются как текстовое выражение для циклов if/while, они преобразуются в booleans. Вы не можете использовать is или == для проверки того, что они оценивают. Вы используете bool( thing )

>>> a = (None,)
>>> bool(a)
True

Также обратите внимание:

>>> 10 == True
False
>>> 10 is True
False
>>> bool(10)
True

Ответ 4

TL; ДР:

if и == - совершенно разные операции. if проверяет значение истины переменной, а == сравнивает две переменные. is также сравнивает две переменные, но сравнивается, если оба ссылаются на один и тот же объект.

Поэтому нет смысла сравнивать переменную с True, False или None, чтобы проверить ее значение истины.

Что происходит, когда if используется для переменной?

В Python проверка типа if неявно получает аргумент bool. Так

if something:

будет (под капотом) выполнен как:

if bool(something):

Обратите внимание, что вы никогда не должны использовать последнее в своем коде, потому что он считается менее pythonic и медленнее (потому что Python использует два bool s: bool(bool(something))). Всегда используйте if something.

Если вам интересно, как это оценивается CPython 3.6:

введите описание изображения здесь

Обратите внимание, что CPython точно не использует hasattr здесь. Он проверяет, реализует ли метод type из x этот метод, но без прохождения метода __getattribute__ (hasattr будет использовать это).

В Python2 метод был вызван __nonzero__, а не __bool__

Что происходит, когда переменные сравниваются с помощью ==?

== будет проверять равенство (часто также называемое "равенством ценности" ). Однако эта проверка равенства не вызывает принуждения операндов (в отличие от других языков программирования). Значимое равенство в Python явно реализовано. Итак, вы можете сделать:

>>> 1 == True  # because bool subclasses int, True is equal to 1 (and False to 0)
True

>>> 1.0 == True  # because float implements __eq__ with int
True

>>> 1+1j == True  # because complex implements __eq__ with int
True

Однако == по умолчанию сравнивает сравнение (is), если сравнение не выполняется ни одним из операндов. Вот почему:

>>> (None, ) == True
False

Потому что tuple не "поддерживает" равенство с int и наоборот. Обратите внимание, что даже сравнение списков с кортежами "неподдерживается":

>>> [None] == (None, )
False

На всякий случай вам интересно, как CPython (3.6) реализует равенство (оранжевые стрелки указывают, вернула ли операция константу NotImplemented):

введите описание изображения здесь

Это только примерно верно, потому что CPython также проверяет, реализует ли type() из value1 или value2 __eq__ (без прохождения метода __getattribute__!) до его вызова (если он существует) или пропущен ( если он не существует).

Обратите внимание, что поведение в Python2 было значительно более продолжительным (по крайней мере, если возвращаемые методы NotImplemented) и Python 2 также поддерживали __cmp__,

Что происходит, когда переменные сравниваются с помощью is?

is обычно упоминается как оператор сравнения ссылочного равенства. Он возвращает только True, если обе переменные относятся к одному и тому же объекту. В общем случае переменные, которые имеют одинаковое значение, могут, тем не менее, ссылаться на разные объекты:

>>> 1 is 1.  # same value, different types
False

>>> a = 500
>>> a is 500  # same value, same type, different instances
False

Обратите внимание, что CPython использует кешированные значения, поэтому иногда переменные, которые должны быть разными, на самом деле являются одним и тем же экземпляром. Поэтому я не использовал 500 is 500 (литералы с одинаковым значением в одной строке всегда равны) и почему я не мог использовать 1 в качестве примера (потому что CPython повторно использует значения от -5 до 256).

Но вернемся к вашим сравнениям: is сравнивает ссылки, это означает, что этого недостаточно, если оба операнда имеют один и тот же тип и значение, но они должны быть одной и той же ссылкой. Учитывая, что они даже не имеют один и тот же тип (вы сравниваете tuple с объектами bool и NoneType), невозможно, чтобы is возвращал True.

Обратите внимание, что True, False и None (а также NotImplemented и Ellipsis) являются константами и одноточечными в CPython. Это не просто оптимизация в этих случаях.

Ответ 5

(None,) является кортежем, который содержит элемент, он не пуст и поэтому не оценивает False в этом контексте.

Ответ 6

Поскольку a=(None,) является кортежем, содержащим один элемент None

Повторите попытку с помощью a=None, и вы увидите, что есть другой результат.

Также попробуйте a=(), который является пустым кортежем. Это значение истинности false

Ответ 7

В Python каждый тип может быть преобразован в bool с помощью функции bool() или __nonzero__ method.

Примеры:

  • Последовательности (списки, строки,...) преобразуются в False, когда они пусты.
  • Целые числа преобразуются в False, когда они равны 0.
  • Вы можете определить это поведение в своих собственных классах, переопределив __nonzero__().

[изменить]

В вашем коде кортеж (None,) преобразуется с помощью bool() в операторы if. Поскольку он не пуст, он принимает значение True.