Вещи 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
.