41 votes

Différence de vérification d'égalité Python

Supposons que nous voulons que le bloc de code à exécuter lorsque les deux 'a' et 'b' sont égaux à 5. Ensuite, nous pouvons écrire comme :

if a == 5 and b == 5:
    # do something

Mais il y a quelques jours, j'ai juste involontairement a écrit une semblable condition de vérifier que :

if a == b and b == 5:
    # do something 

ce qui m'a fait penser, quelle est la différence entre les deux ? Aussi, il existe une autre façon,

if a == b == 5:
    # do something

Quelle est la différence, une différence en termes de processus d'évaluation ou de exécution ou le temps pris ? et aussi celui qui est le mieux ou ce qui est mieux pour l'utiliser?

Est-ce lié à la notion de transitivité ?

44voto

Jasper Points 1377

Depuis qu'ils sont fondamentalement équivalent, vous pourriez aussi envisager la manière dont vous lisez/penser le code:

if a == 5 and b == 5:
  # do something

peut être lu comme "si a équivaut 5 et b équivaut 5, puis de le faire ...". Vous devez penser/conclure, que puis aussi a sera égal à b.

C'est l'opposé de l'exemple suivant:

if a == b and b == 5:
  # do something 

Ce lit que "si a est égal à b et b égal à 5" et vous avez à conclure que puis aussi a sera égal à 5

C'est pourquoi je préfère la dernier exemple:

if a == b == 5:
  # do something

Si vous êtes familier avec Python (grâce à Itzkata), il est immédiatement clair que tous les trois choses doivent être égaux (à l' 5). Si toutefois, les personnes ayant moins d'expérience en Python (mais la programmation des compétences dans d'autres langues) voir cela, ils peuvent évaluer ce à

if (a == b) == 5:

ce qui permettrait de comparer le résultat booléen de la première comparaison avec l'entier 5, ce qui n'est pas ce que Python ne et pourrait conduire à des résultats différents (par exemple avec a=0, b=0: a==b==0 est vraie alors (a==b) == 0 ne l'est pas!

Le manuel dit:

Il y a huit opérations de comparaison en Python. Ils ont tous les de même priorité (ce qui est plus élevé que celui des opérations Booléennes). Des comparaisons peuvent être enchaînées de façon arbitraire; par exemple, x < y <= z est équivalent à x < y et y <= z, sauf que y est évaluée qu'une seule fois (mais dans les deux cas, z n'est pas évalué si x < y est trouvé être false).

Il pourrait même y avoir une différence, par exemple si evaulating b dans votre exemple, serait un effet secondaire.

Concernant la transitivité, vous avez raison.

20voto

devnull Points 45016

Si vous avez plus de variables à tester, l'utilisation de all peut être légèrement plus lisible:

 if all(i==5 for i in [a,b,c,d]):
    # do something
 

15voto

Roberto Reale Points 3256

En ce qui concerne les nombres entiers, il n'y a pas de différence, en termes de performances, entre les deux premières comparaisons.

La troisième comparaison est cependant différente; car un peu plus jouer avec la pile s'implique. En effet, le code

 import dis

def comparison_1(a, b):
    if a == 5 and b == 5:
        pass

def comparison_2(a, b):
    if a == b and b == 5:
        pass

def comparison_3(a, b):
    if a == b == 5:
        pass

print("*** First comparison ***")
dis.dis(comparison_1)

print("\n*** Second comparison ***")
dis.dis(comparison_2)

print("\n*** Third comparison ***")
dis.dis(comparison_3)
 

résultats

 *** First comparison ***
  4           0 LOAD_FAST                0 (a)
              3 LOAD_CONST               1 (5)
              6 COMPARE_OP               2 (==)
              9 POP_JUMP_IF_FALSE       27
             12 LOAD_FAST                1 (b)
             15 LOAD_CONST               1 (5)
             18 COMPARE_OP               2 (==)
             21 POP_JUMP_IF_FALSE       27

  5          24 JUMP_FORWARD             0 (to 27)
        >>   27 LOAD_CONST               0 (None)
             30 RETURN_VALUE        

*** Second comparison ***
  8           0 LOAD_FAST                0 (a)
              3 LOAD_FAST                1 (b)
              6 COMPARE_OP               2 (==)
              9 POP_JUMP_IF_FALSE       27
             12 LOAD_FAST                1 (b)
             15 LOAD_CONST               1 (5)
             18 COMPARE_OP               2 (==)
             21 POP_JUMP_IF_FALSE       27

  9          24 JUMP_FORWARD             0 (to 27)
        >>   27 LOAD_CONST               0 (None)
             30 RETURN_VALUE        

*** Third comparison ***
 12           0 LOAD_FAST                0 (a)
              3 LOAD_FAST                1 (b)
              6 DUP_TOP             
              7 ROT_THREE           
              8 COMPARE_OP               2 (==)
             11 JUMP_IF_FALSE_OR_POP    23
             14 LOAD_CONST               1 (5)
             17 COMPARE_OP               2 (==)
             20 JUMP_FORWARD             2 (to 25)
        >>   23 ROT_TWO             
             24 POP_TOP             
        >>   25 POP_JUMP_IF_FALSE       31

 13          28 JUMP_FORWARD             0 (to 31)
        >>   31 LOAD_CONST               0 (None)
             34 RETURN_VALUE        
 

7voto

wheaties Points 20917

Ça dépend. Vous pouvez écrire votre propre __eq__ qui vous permet de vous comparer aux choses et aux choses:

  class NonNegativeInt(object):
   def __init__(self, value):
     if value < 0:
       raise Exception("Hey, what the...")
     self.value = value

   def __eq__(self, that):
     if isinstance(that, int):
       return self.value == that
     elif isinstance(that, NonNegativeInt):
       return self.value == that.value
     else:
       raise ArgumentError("Not an acceptible argument", "__eq__", that)
 

qui fonctionnerait différemment en comparant "b" à "a" et "b" à un "int". Par conséquent, a == b pourrait être faux tandis que a == 5 and b == 5 pourrait être vrai.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X