Étant donné 2 valeurs int, renvoie True si l'une est négative et l'autre est positive

def logical_xor(a, b): # for example, -1 and 1
    print (a < 0) # evaluates to True
    print (b < 0) # evaluates to False
    print (a < 0 != b < 0) # EVALUATES TO FALSE! why??? it's True != False
    return (a < 0 != b < 0) # returns False when it should return True

print ( logical_xor(-1, 1) ) # returns FALSE!

# now for clarification

print ( True != False) # PRINTS TRUE!

Quelqu'un Pourrait-il expliquer ce qui se passe? J'essaie de faire un one liner:

lambda a, b: (a < 0 != b < 0)
25
demandé sur tzaman 2015-04-22 10:27:00

4 réponses

Tous les opérateurs de comparaison en Python ont la même priorité . de plus, Python fait des comparaisons chaînées. Ainsi,

(a < 0 != b < 0)

Se décompose comme suit:

(a < 0) and (0 != b) and (b < 0)

Si l'un d'entre eux est faux, le résultat total de l'expression sera False.

Ce que vous voulez faire est d'évaluer chaque état séparément, comme suit:

(a < 0) != (b < 0)

Autres variantes, à partir des commentaires:

(a < 0) is not (b < 0) # True and False are singletons so identity-comparison works

(a < 0) ^ (b < 0) # bitwise-xor does too, as long as both sides are boolean

(a ^ b < 0) # or you could directly bitwise-xor the integers; 
            # the sign bit will only be set if your condition holds
            # this one fails when you mix ints and floats though

(a * b < 0) # perhaps most straightforward, just multiply them and check the sign
31
répondu tzaman 2015-04-22 13:48:15

Votre code ne fonctionne pas comme prévu, car != prend supérieur préséance que a < 0 et b < 0. Comme itzmeontv le suggère dans sa réponse, vous pouvez simplement décider de la priorité vous-même en entourant les composants logiques avec des parenthèses:

(a < 0) != (b < 0)

Votre code tente d'évaluer a < (0 != b) < 0

[MODIFIER]

Comme tzaman le souligne à juste titre, les opérateurs ont la même priorité, mais votre code tente d'évaluer (a < 0) and (0 != b) and (b < 0). Entourant votre les composants logiques avec des parenthèses résoudront ceci:

(a < 0) != (b < 0)

La priorité de l'Opérateur: https://docs.python.org/3/reference/expressions.html#operator-precedence

Comparaisons (par exemple chaînage): https://docs.python.org/3/reference/expressions.html#not-in

8
répondu EvenLisle 2015-04-22 12:03:01

Vous pouvez utiliser ceci

return (a < 0) != (b < 0)

Comparaisons peuvent être enchaînés de manière arbitraire, par exemple, x

Donc ça devient

(a < 0) and (0 != b) and (b < 0)

Voir https://docs.python.org/3/reference/expressions.html#not-in

5
répondu itzMEonTV 2015-04-22 12:18:03

En Python, les opérateurs de comparaison ont la même priorité, et ils sont non associatifs. Il existe une règle distincte pour les séquences d'opérateurs de comparaison, la règle de chaînage. la documentation Python indique à ce sujet:

Si a, b, c, ..., y, z sont des expressions et op1, op2, ..., opN sont les opérateurs de comparaison, puis un op1 b op2 c ... y opN z est équivalent à a op1 b and b op2 c and ... y opN z, sauf que chaque expression est évaluée au plus une fois.

En outre, a op1 b and b op2 c and ... y opN z évalue de gauche à droite.

 a < 0 and 0 != b and b < 0  

a < 0 va évalué à False, et l'évaluation ultérieure sera arrêtée en raison de évaluation de court-circuit . Ainsi, l'expression entière sera évaluée comme False.

0
répondu haccks 2015-04-22 16:26:42