Почему... == True возвращает False в Python 3?

Я изучаю python, но меня немного смущает следующий результат.

In [41]: 1 == True
Out[41]: True

In [42]: if(1):
    ...:     print('111')
    ...:     
111

In [43]: ... == True
Out[43]: False <===== why this is False while '1 == True' is True in previous sample

In [44]: if (...): <==== here ... just behaves like True
    ...:     print('...')
    ...:     
...

Согласно документации, ... имеет значение истины True.

Но я все еще чувствую, что приведенный выше код немного несовместим.

... И что-то более интересное:

In [48]: 2==True
Out[48]: False <===== why 1==True returns True while 2==True returns False?

In [49]: if(2):
    ...:     print('222')
    ...:     
222

Ответ 1

Вы смешиваете две концепции: тестирование равенства и тестирование истины. Они не совпадают с Python.

Я думаю, что вызвало вопрос, что Python делает неявное кастинг, когда вы делаете if something (он передает что-то bool), но не делать неявное литье, когда вы делаете something1 == something2.

Модель данных Pythons на самом деле объясняет, как эти операции выполняются:

Проверка правды

  • Он начинается с проверки того, реализует ли объект метод __bool__, и если он использует это, возвращается возвращаемое логическое значение.
  • Если он не определяет метод __bool__, он смотрит на метод __len__. Если он будет реализован, он будет использовать результат len(obj) != 0.
  • Если он не имеет ни объект, который считается True.

Для целых чисел метод __bool__ возвращает True, за исключением случаев, когда целочисленное значение 0 (тогда оно False).

Объект Ellipsis (... является объектом Ellipsis), с другой стороны не реализует __bool__ или __len__, поэтому он всегда True.

Проверка равенства

Тестирование равенства использует метод __eq__ аргументов как. Это скорее цепочка операций:

  • Он проверяет, реализует ли первый операнд __eq__, когда второй операнд передается как аргумент.
  • Если это не так, он проверяет, реализует ли второй операнд __eq__, когда первый операнд передается как аргумент.
  • Если это не так, то Python проверяет идентификатор объекта (если они являются одним и тем же объектом - похожим на сравнение указателей на языках C)

Порядок этих операций может варьироваться. 1

Для встроенных типов Python эти операции явно реализованы. Например int egers реализуют __eq__, но CHECK_BINOP гарантирует, что он возвращает NotImplemented, если другой не является int eger.

Объект Ellipsis вообще не реализует __eq__.

Поэтому, когда вы сравниваете целые числа и Ellipsis Python всегда будет возвращаться к идентификатору объекта, и поэтому он всегда будет возвращать False.

С другой стороны, bool eans являются подклассом int egers, поэтому они фактически сравниваются с int (иначе они являются int). Булевы реализованы как 1 (True) и 0 (False). Поэтому они сравнивают равные:

>>> 1 == True
True
>>> 0 == False
True

>>> 1 == False
False
>>> 0 == True
False

Хотя исходный код, вероятно, трудно понять, я надеюсь, что я достаточно хорошо объяснил концепции (исходный код для реализации CPython, реализация в других реализациях Python, таких как PyPy, IronPython может отличаться!). Важным выводом должно быть то, что Python не делает неявных преобразований при проверке равенства, а тестирование равенства не связано вообще с тестированием значений истинности. Внедрены встроенные типы, которые почти всегда дают ощутимые результаты:

  • все числовые типы реализуют равенство в некотором роде (поплавки сравниваются с целыми числами, сложным по сравнению с целыми числами и поплавками)
  • и все не-ноль и не пусто - truthy.

Однако, если вы создадите свои собственные классы, вы можете переопределить тестирование равенства и истинности, как вам нравится (и затем вы можете распространять много путаницы)!


1 В некоторых случаях порядок изменяется:

  • Если второй операнд является подклассом первого операнда, первые два шага меняются на противоположные.
  • Для некоторых неявных проверок равенства идентификатор объекта проверяется перед вызовом методов __eq__. Например, при проверке, находится ли какой-либо элемент в списке, т.е. 1 in [1,2,3].

Ответ 2

Любой объект может быть протестирован для "правдивость" :

Любой объект может быть проверен на значение истины, для использования в условии if или while или в качестве операнда следующих операций Boolean. Следующие значения считаются ложными:

  • None

  • False

  • нуль любого числового типа, например, 0, 0.0, 0j.

  • любая пустая последовательность, например, '',(), [].

  • любое пустое отображение, например {}.

  • экземпляры пользовательских классов, если класс определяет метод bool() или len(), когда этот метод возвращает целое число 0 или bool значение False. [1]

Все остальные значения считаются истинными, поэтому объекты многих типов всегда верны.

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

Так что не трудно понять, что if ... войдет в ветку. Объект Ellipsis считается true. Однако это не означает, что он должен быть равен true. Просто bool(...) == True!

if будет неявно вызывать bool при условии, поэтому:

if ...:
    # something

будет оцениваться так, как если бы вы написали:

if bool(...):
    # something

и

>>> bool(...)
True
>>> bool(1)
True
>>> bool(2)
True

Однако там уловка здесь. true равно 1 и False, равному 0, но это только потому, что bool подклассы int eger в python.

Ответ 3

В python большинство (все?) объектов имеют значение bool. Значение "имеет значение истины True" означает, что bool(obj) имеет значение True.

С другой стороны, True во многих случаях рассматривается как 1False как 0), который вы можете видеть, когда делаете что-то вроде:

sum([True, True, False])
# (1 + 1 + 0) -> 2

Вот почему вы получаете 1 == TrueTrue

В документации есть более явное пояснение:

Логические значения - это два константных объекта False и True. Они используются для представления значений истинности (хотя другие значения также могут считаться ложными или истинными). В числовых контекстах (например, при использовании в качестве аргумента для арифметического оператора) они ведут себя как целые числа 0 и 1 соответственно

Из type-hierarchy сам в документах:

Они представляют значения истинности False и True. Два объекта, представляющие значения False и True, являются единственными булевыми объектами. Булевский тип является подтипом целочисленного типа, а Логические значения ведут себя как значения 0 и 1, соответственно, почти во всех контекстах, причем исключение состоит в том, что при преобразовании в строку строки "False" или "True", соответственно.

Ответ 4

Я считаю, что 1 == True вот что странно, а не ... != True.

1 равен True, потому что в Python булевы являются подклассом целых чисел (из-за PEP-285). Смотрите сами:

>>> issubclass(bool, int)
True