web-dev-qa-db-fra.com

Python sinon == vs si! =

Quelle est la différence entre ces deux lignes de code:

if not x == 'val':

et

if x != 'val':

Est-ce que l'un est plus efficace que l'autre?

Serait-il préférable d'utiliser

if x == 'val':
    pass
else:
174
lafferc

Utilisation de dis pour consulter le bytecode généré pour les deux versions:

not ==

_  4           0 LOAD_FAST                0 (foo)
              3 LOAD_FAST                1 (bar)
              6 COMPARE_OP               2 (==)
              9 UNARY_NOT           
             10 RETURN_VALUE   
_

!=

_  4           0 LOAD_FAST                0 (foo)
              3 LOAD_FAST                1 (bar)
              6 COMPARE_OP               3 (!=)
              9 RETURN_VALUE   
_

Ce dernier a moins d’opérations et devrait donc être légèrement plus efficace.


Il a été souligné dans les commentaires (merci, @ Quincunx ) que lorsque vous avez _if foo != bar_ vs. _if not foo == bar_ le nombre d'opérations est exactement le De même, il est juste que le _COMPARE_OP_ change et _POP_JUMP_IF_TRUE_ bascule vers _POP_JUMP_IF_FALSE_:

not ==:

_  2           0 LOAD_FAST                0 (foo)
              3 LOAD_FAST                1 (bar)
              6 COMPARE_OP               2 (==)
              9 POP_JUMP_IF_TRUE        16
_

!=

_  2           0 LOAD_FAST                0 (foo)
              3 LOAD_FAST                1 (bar)
              6 COMPARE_OP               3 (!=)
              9 POP_JUMP_IF_FALSE       16
_

Dans ce cas, à moins d'une différence dans la quantité de travail requise pour chaque comparaison, il est peu probable que vous constatiez une différence de performances.


Cependant, notez que les deux versions ne seront pas toujours logiquement identiques , car cela dépend des implémentations de ___eq___ et ___ne___ pour les objets en question. Per la documentation du modèle de données :

Il n'y a pas de relations implicites entre les opérateurs de comparaison. La vérité de _x==y_ n'implique pas que _x!=y_ est faux.

Par exemple:

_>>> class Dummy(object):
    def __eq__(self, other):
        return True
    def __ne__(self, other):
        return True


>>> not Dummy() == Dummy()
False
>>> Dummy() != Dummy()
True
_

Enfin et peut-être le plus important: en général, où les deux sont logiquement identiques, x != y_ EST BEAUCOUP PLUS LISIBLE QUE _not x == y.

219
jonrsharpe

@jonrsharpe a une excellente explication de ce qui se passe. Je pensais montrer la différence de temps lorsque chacune des 3 options était exécutée 10 000 000 fois (assez pour montrer une légère différence).

Code utilisé:

def a(x):
    if x != 'val':
        pass


def b(x):
    if not x == 'val':
        pass


def c(x):
    if x == 'val':
        pass
    else:
        pass


x = 1
for i in range(10000000):
    a(x)
    b(x)
    c(x)

Et les résultats du profileur cProfile:

enter image description here

Nous pouvons donc voir qu’il existe une très petite différence d’environ 0,7% entre if not x == 'val': et if x != 'val':. Parmi ceux-ci, if x != 'val': est le plus rapide.

Cependant, le plus surprenant, nous pouvons voir que

if x == 'val':
        pass
    else:

est en fait le plus rapide et bat if x != 'val': de ~ 0,3%. Ce n'est pas très lisible, mais je suppose que si vous vouliez une amélioration des performances négligeable, vous pourriez vous engager dans cette voie.

29
Red Shift

Dans le premier, Python doit exécuter une opération de plus que nécessaire (au lieu de simplement vérifier qu'il n'est pas égal à, il doit vérifier s'il n'est pas vrai qu'il soit égal, donc une opération de plus). Il serait impossible de faire la différence d'une exécution, mais si elle était exécutée plusieurs fois, la seconde serait plus efficace. Globalement, j'utiliserais le second, mais mathématiquement, ils sont identiques.

6
JediPythonClone
>>> from dis import dis
>>> dis(compile('not 10 == 20', '', 'exec'))
  1           0 LOAD_CONST               0 (10)
              3 LOAD_CONST               1 (20)
              6 COMPARE_OP               2 (==)
              9 UNARY_NOT
             10 POP_TOP
             11 LOAD_CONST               2 (None)
             14 RETURN_VALUE
>>> dis(compile('10 != 20', '', 'exec'))
  1           0 LOAD_CONST               0 (10)
              3 LOAD_CONST               1 (20)
              6 COMPARE_OP               3 (!=)
              9 POP_TOP
             10 LOAD_CONST               2 (None)
             13 RETURN_VALUE

Ici, vous pouvez voir que not x == y a une instruction de plus que x != y. La différence de performance sera donc très faible dans la plupart des cas, à moins que vous ne fassiez des millions de comparaisons. Même dans ce cas, cela ne sera probablement pas la cause d'un goulot d'étranglement.

5
kylie.a

Une note supplémentaire, étant donné que les autres réponses à votre question ont pour la plupart bien répondu correctement, est que si une classe définit uniquement __eq__() et non __ne__(), votre COMPARE_OP (!=) exécutera __eq__() et annulera il. À ce moment-là, votre troisième option sera probablement un peu plus efficace, mais ne devrait être envisagée que si vous BESOIN de la vitesse, car il est difficile à comprendre rapidement.

5
Jacob Zimmerman

Il s'agit de votre façon de le lire. not l'opérateur est dynamique, c'est pourquoi vous pouvez l'appliquer dans

if not x == 'val':

Mais != pourrait être lu dans un meilleur contexte en tant qu’opérateur qui fait le contraire de ce que == fait.

3
Himanshu Mishra

Je veux développer mon commentaire de lisibilité ci-dessus.

Encore une fois, je suis tout à fait d’accord avec le fait que la lisibilité prévaut sur d’autres préoccupations (non liées à la performance).

Ce que je voudrais souligner, c'est que le cerveau interprète "positif" plus vite que "négatif". Par exemple, "arrêter" vs "ne pas y aller" (un exemple plutôt moche en raison de la différence dans le nombre de mots).

Alors donné un choix:

if a == b
    (do this)
else
    (do that)

est préférable à l'équivalent fonctionnel:

if a != b
    (do that)
else
    (do this)

Moins de lisibilité/compréhensibilité conduit à plus de bugs. Peut-être pas dans le codage initial, mais la maintenance (pas aussi intelligente que vous!) Change ...

1
Alan Jay Weiner