Почему выражение 0 <0 == 0 возвращает False в Python?

Заглянув в Queue.py в Python 2.6, я нашел эту конструкцию, которая мне показалась немного странной:

def full(self):
    """Return True if the queue is full, False otherwise
    (not reliable!)."""
    self.mutex.acquire()
    n = 0 < self.maxsize == self._qsize()
    self.mutex.release()
    return n

Если maxsize равно 0, очередь не заполняется.

Мой вопрос в том, как он работает в этом случае? Как 0 < 0 == 0 считается False?

>>> 0 < 0 == 0
False
>>> (0) < (0 == 0)
True
>>> (0 < 0) == 0
True
>>> 0 < (0 == 0)
True

Ответ 1

Я считаю, что у Python есть специальная обработка сообщений для последовательностей реляционных операторов, чтобы упростить их сравнение. Гораздо приятнее сказать 0 < x <= 5, чем сказать (0 < x) and (x <= 5).

Они называются скованные сравнения. И это ссылка на документацию для них.

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

Ответ 2

Поскольку

(0 < 0) and (0 == 0)

есть False. Вы можете связать вместе операторы сравнения, и они автоматически расширяются в попарные сравнения.


РЕДАКТИРОВАНИЕ - разъяснение прав и прав в Python

В Python True и False есть только экземпляры bool, который является подклассом int. Другими словами, True действительно всего 1.

Точка в том, что вы можете использовать результат булевого сравнения точно так же, как целое число. Это приводит к запутыванию таких вещей, как

>>> (1==1)+(1==1)
2
>>> (2<1)<1
True

Но это произойдет, только если вы скопируете сравнения, чтобы они сначала оценивались. В противном случае Python расширит операторы сравнения.

Ответ 3

Странное поведение вашего опыта происходит от способности питонов к условиям цепи. Поскольку он находит, что 0 не меньше 0, он решает, что все выражение принимает значение false. Как только вы разбиваете это на отдельные условия, вы меняете функциональность. Первоначально он в основном тестирует, что a < b && b == c для вашего исходного утверждения a < b == c.

Другой пример:

>>> 1 < 5 < 3
False

>>> (1 < 5) < 3
True

Ответ 4

>>> 0 < 0 == 0
False

Это скованное сравнение. Он возвращает true, если каждое попарное сравнение по очереди истинно. Это эквивалентно (0 < 0) and (0 == 0)

>>> (0) < (0 == 0)
True

Это эквивалентно 0 < True, который оценивается как True.

>>> (0 < 0) == 0
True

Это эквивалентно False == 0, который оценивается как True.

>>> 0 < (0 == 0)
True

Эквивалент 0 < True, который, как указано выше, имеет значение True.

Ответ 5

Глядя на разборку (коды байтов), очевидно, что 0 < 0 == 0 есть False.

Вот анализ этого выражения:

>>>import dis

>>>def f():
...    0 < 0 == 0

>>>dis.dis(f)
  2      0 LOAD_CONST               1 (0)
         3 LOAD_CONST               1 (0)
         6 DUP_TOP
         7 ROT_THREE
         8 COMPARE_OP               0 (<)
        11 JUMP_IF_FALSE_OR_POP    23
        14 LOAD_CONST               1 (0)
        17 COMPARE_OP               2 (==)
        20 JUMP_FORWARD             2 (to 25)
   >>   23 ROT_TWO
        24 POP_TOP
   >>   25 POP_TOP
        26 LOAD_CONST               0 (None)
        29 RETURN_VALUE

Отметьте строки 0-8: эти строки проверяют, есть ли 0 < 0, который явно возвращает False в стек python.

Теперь обратите внимание на строку 11: JUMP_IF_FALSE_OR_POP 23 Это означает, что если 0 < 0 возвращает False выполнить переход к строке 23.

Теперь 0 < 0 является False, поэтому выполняется переход, который оставляет стек с False, который является возвращаемым значением для всего выражения 0 < 0 == 0, хотя часть == 0 isn ' t даже проверено.

Итак, в заключение, ответ подобен сказанному в других ответах на этот вопрос. 0 < 0 == 0 имеет особое значение. Компилятор оценивает это на два термина: 0 < 0 и 0 == 0. Как и с любыми сложными булевыми выражениями с and между ними, если первое не удается, второе не проверяется даже.

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

Ответ 6

Возможно, эта выдержка из docs может помочь:

Это так называемые "богатые сравнения" и называются для предпочтительных операторов сравнения ниже __cmp__(). Переписка между символами оператора и методом имена следующие: x<y calls x.__lt__(y), x<=y вызывает x.__le__(y), x==y вызывает x.__eq__(y), x!=y и x<>yвызов x.__ne__(y), x>y x.__gt__(y) и x>=y x.__ge__(y).

Богатый метод сравнения может вернуться singleton NotImplemented, если он не выполняет операцию для заданная пара аргументов. От соглашения, False и True являются вернулся для успешного сравнения. Однако эти методы могут возвращать любые значение, поэтому, если оператор сравнения используется в булевом контексте (например, в условие оператора if), Python вызовет bool() для значения определить, является ли результат истинным или ложь.

Нет подразумеваемых отношений среди операторов сравнения. истина x==y не означает, что x!=yfalse. Соответственно, при определении __eq__(), следует также определить __ne__(), чтобы операторы действовали должным образом. См. Пункт на __hash__() для некоторых важных заметок по созданию хешируемых объектов, которые поддержка пользовательских операций сравнения и могут использоваться в качестве словарных клавиш.

Нет версий с замененным аргументом из этих методов (используется, когда левый аргумент не поддерживает но правильный аргумент делает); скорее, __lt__() и __gt__()отражают друг друга, __le__()и __ge__() являются друг другом отражение и __eq__() и __ne__()являются их собственным отражением.

Аргументы для богатых методов сравнения никогда не принуждаются.

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

Сравнение может быть прикованным произвольно, например, x < y <= z является эквивалентно x < y and y <= z, кроме что y оценивается только один раз (но в оба случая z вообще не оцениваются когда x < y считается ложным).

Формально, если a, b, c,..., y, z являются выражения и op1, op2,..., opN являются операторы сравнения, то op1 b op2 c... y opN z эквивалентно op1 b и b op2 c и... y opN z, кроме что каждое выражение оценивается в самый раз.

Ответ 7

Как упоминалось выше, x comparison_operator y comparison_operator z является синтаксическим сахаром для (x comparison_operator y) and (y comparison_operator z) с бонусом, что y оценивается только один раз.

Итак, ваше выражение 0 < 0 == 0 действительно (0 < 0) and (0 == 0), которое оценивается как False and True, которое просто False.

Ответ 8

Вот он во всей красе.

>>> class showme(object):
...   def __init__(self, name, value):
...     self.name, self.value = name, value
...   def __repr__(self):
...     return "<showme %s:%s>" % (self.name, self.value)
...   def __cmp__(self, other):
...     print "cmp(%r, %r)" % (self, other)
...     if type(other) == showme:
...       return cmp(self.value, other.value)
...     else:
...       return cmp(self.value, other)
... 
>>> showme(1,0) < showme(2,0) == showme(3,0)
cmp(<showme 1:0>, <showme 2:0>)
False
>>> (showme(1,0) < showme(2,0)) == showme(3,0)
cmp(<showme 1:0>, <showme 2:0>)
cmp(<showme 3:0>, False)
True
>>> showme(1,0) < (showme(2,0) == showme(3,0))
cmp(<showme 2:0>, <showme 3:0>)
cmp(<showme 1:0>, True)
True
>>> 

Ответ 9

Я думаю, что Python делает это странно между магией. То же, что и 1 < 2 < 3 означает, что 2 находится между 1 и 3.

В этом случае, я думаю, что выполнение [middle 0] больше, чем [left 0] и равно [right 0]. Среднее 0 не больше, чем левое 0, поэтому оно принимает значение false.