valores usar relacionales operadores operaciones not logicas funcion exclusivo como booleanos bool binarios binarias python

python - usar - valores booleanos y operaciones logicas



¿Por qué la expresión 0<0== 0 devuelve False en Python? (9)

Aquí está, en todo su esplendor.

>>> 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 >>>

Mirando en Queue.py en Python 2.6, encontré este constructo que encontré un poco extraño:

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

Si maxsize es 0, la cola nunca está llena.

Mi pregunta es ¿cómo funciona para este caso? ¿Cómo se considera 0 < 0 == 0 falso?

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


Como otros mencionaron x comparison_operator y comparison_operator z es azúcar sintáctica para (x comparison_operator y) and (y comparison_operator z) con la bonificación de que y solo se evalúa una vez.

Entonces su expresión 0 < 0 == 0 es realmente (0 < 0) and (0 == 0) , que evalúa False and True que es False .


Creo que Python tiene manejo especial de casos para secuencias de operadores relacionales para hacer que las comparaciones de rango sean fáciles de expresar. Es mucho más agradable poder decir 0 < x <= 5 que decir (0 < x) and (x <= 5) .

Estas se llaman comparaciones encadenadas . Y ese es un enlace a la documentación para ellos.

Con los otros casos de los que habla, el paréntesis obliga a un operador relacional a aplicarse antes que al otro, por lo que ya no son comparaciones encadenadas. Y como True y False tienen valores como enteros, obtienes las respuestas que haces de las versiones entre paréntesis.


El extraño comportamiento que experimentas proviene de la habilidad de las pitones para encadenar las condiciones. Como encuentra que 0 no es menor que 0, decide que la expresión completa se evalúa como falsa. Tan pronto como divide esto en condiciones separadas, está cambiando la funcionalidad. Inicialmente, esencialmente está probando que a < b && b == c para su enunciado original de a < b == c .

Otro ejemplo:

>>> 1 < 5 < 3 False >>> (1 < 5) < 3 True


Estoy pensando que Python lo está haciendo entre la magia. Igual que 1 < 2 < 3 significa que 2 está entre 1 y 3.

En este caso, creo que está haciendo que [middle 0] sea mayor que [left 0] e igual a [right 0]. El medio 0 no es mayor que el 0 restante, por lo que se evalúa como falso.


Mirando el desmontaje (los códigos de bytes) es obvio por qué 0 < 0 == 0 es False .

Aquí hay un análisis de esta expresión:

>>>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

Observe las líneas 0-8: estas líneas comprueban si 0 < 0 que obviamente devuelve False en la pila de python.

Ahora observe la línea 11: JUMP_IF_FALSE_OR_POP 23 Esto significa que si 0 < 0 devuelve False realice un salto a la línea 23.

Ahora, 0 < 0 es False , por lo que se toma el salto, que deja la pila con un valor False que es el valor de retorno para toda la expresión 0 < 0 == 0 , aunque la parte == 0 ni siquiera está marcada.

Entonces, para concluir, la respuesta es como se dijo en otras respuestas a esta pregunta. 0 < 0 == 0 tiene un significado especial. El compilador evalúa esto en dos términos: 0 < 0 y 0 == 0 . Al igual que con cualquier expresión booleana compleja con and entre ellos, si la primera falla, entonces la segunda ni siquiera está marcada.

Espera que esto aclare un poco las cosas, y realmente espero que el método que utilicé para analizar este comportamiento inesperado aliente a otros a intentar lo mismo en el futuro.


Porque

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

es False Puede encadenar operadores de comparación y se expanden automáticamente en las comparaciones por pares.

EDITAR - aclaración sobre True y False en Python

En Python True y False son solo instancias de bool , que es una subclase de int . En otras palabras, True realmente es solo 1.

El objetivo de esto es que puedes usar el resultado de una comparación booleana exactamente como un entero. Esto lleva a cosas confusas como

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

Pero esto solo ocurrirá si entrelazan las comparaciones para que se evalúen primero. De lo contrario, Python expandirá los operadores de comparación.


tal vez este extracto de los docs puede ayudar:

Estos son los llamados métodos de "comparación enriquecida", y se llaman para operadores de comparación con preferencia a __cmp__() continuación. La correspondencia entre los símbolos del operador y los nombres de los métodos es la siguiente: x<y llamadas x.__lt__(y) , x<=y llamadas x.__le__(y) , x==y llamadas x.__eq__(y) , x!=y y x<>y llamada x.__ne__(y) , x>y llama x.__gt__(y) , x>=y llama x.__ge__(y) .

Un método de comparación rico puede devolver el singleton NotImplemented si no implementa la operación para un par de argumentos dado. Por convención, False y True se devuelven para una comparación exitosa. Sin embargo, estos métodos pueden devolver cualquier valor, por lo que si el operador de comparación se usa en un contexto booleano (por ejemplo, en la condición de una instrucción if), Python llamará a bool() sobre el valor para determinar si el resultado es verdadero o falso .

No hay relaciones implícitas entre los operadores de comparación. La verdad de x==y no implica que x!=y sea ​​falso. En consecuencia, al definir __eq__() , también se debe definir __ne__() para que los operadores se comporten como se espera. Consulte el párrafo en __hash__() para obtener algunas notas importantes sobre la creación de objetos con capacidad de manipulación que admiten operaciones de comparación personalizadas y que se pueden usar como claves del diccionario.

No hay versiones de argumentos intercambiados de estos métodos (para usar cuando el argumento de la izquierda no admite la operación pero sí el argumento de la derecha); más bien, __lt__() y __gt__() son reflejo el uno del otro, __le__() y __ge__() son reflejo el uno del otro, y __eq__() y __ne__() son su propio reflejo.

Los argumentos a los métodos de comparación ricos nunca se fuerzan.

Estas fueron comparaciones, pero ya que está encadenando comparaciones , debe saber que:

Las comparaciones se pueden encadenar arbitrariamente, por ejemplo, x < y <= z es equivalente a x < y and y <= z , excepto que y se evalúa solo una vez (pero en ambos casos z no se evalúa cuando x <y se encuentra ser falso).

Formalmente, si a, b, c, ..., y, z son expresiones y op1, op2, ..., opN son operadores de comparación, entonces a op1 b op2 c ... y opN z es equivalente a op1 b y b op2 c y ... y opN z, excepto que cada expresión se evalúa como máximo una vez.


>>> 0 < 0 == 0 False

Esta es una comparación encadenada. Devuelve verdadero si cada comparación pairwise es verdadera a su vez. Es el equivalente a (0 < 0) and (0 == 0)

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

Esto es equivalente a 0 < True que se evalúa como Verdadero.

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

Esto es equivalente a False == 0 que se evalúa como True.

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

Equivalente a 0 < True que, como se indica arriba, se evalúa como Verdadero.