Python se non == vs se !=

Qual è la differenza tra queste due linee di codice:

if not x == 'val':

e

if x != 'val':

È una più efficiente rispetto agli altri?

Sarebbe meglio usare

if x == 'val':
    pass
else:
  • Il migliore è quello che si può leggere, dubito che il tuo programma di collo di bottiglia sarà qui
  • Questa domanda mi interessa la “x non in elenco” e “non x in lista” case
  • essi sono interpretati in modo identico.
  • di riferimento per il mio commento di cui sopra: stackoverflow.com/q/8738388/3001761
  • il tuo link è di circa sottostringhe. Ho pensato di collezioni(elenco/dict/set). In ogni caso – chiarisce il senso, grazie!
  • e ‘ lo stesso per coloro che, troppo; è come la sintassi è interpretato, non importa che cosa i due operandi sono.
  • Il not x == 'val' è un po ‘ lento per essere analizzati rispetto al x != 'val', ma la differenza di tempo è di oltre misura. L’effettivo tempo di esecuzione è uguale.

InformationsquelleAutor lafferc | 2015-06-24



7 Replies
  1. 219

    Utilizzando dis a guardare il bytecode generato per le due versioni:

    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   

    Quest’ultimo ha un minor numero di operazioni, e quindi è probabile che sia un po ‘ più efficiente.


    È stato sottolineato nel commments (grazie, @Quinconce) nel caso in cui tu if foo != bar vs if not foo == bar il numero di operazioni è esattamente lo stesso, solo che il COMPARE_OP modifiche e POP_JUMP_IF_TRUE passa a 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

    In questo caso, a meno che non ci fosse una differenza nella quantità di lavoro richiesto per ogni confronto, è improbabile che si vedono nessuna differenza di prestazioni a tutti.


    Si noti, tuttavia, che le due versioni non sempre logicamente identica, in quanto dipende da implementazioni di __eq__ e __ne__ per gli oggetti in questione. Per il modello di dati di documentazione:

    Non ci sono implicite le relazioni tra gli operatori di confronto. Il
    la verità di x==y non implica che x!=y è falso.

    Per esempio:

    >>> class Dummy(object):
        def __eq__(self, other):
            return True
        def __ne__(self, other):
            return True
    
    
    >>> not Dummy() == Dummy()
    False
    >>> Dummy() != Dummy()
    True

    Infine, e forse più importante: in generale, dove i due sono logicamente identica, x != y è molto più leggibile rispetto not x == y.

    • In pratica, ogni classe che ha __eq__ incoerente con __ne__ è flat-out rotto.
    • Si prega di notare che non è sempre vero che not x == y ha in più di istruzione. Quando ho messo il codice in un if, si è scoperto che entrambi hanno lo stesso numero di istruzioni, solo uno aveva POP_JUMP_IF_TRUE e l’altro POP_JUMP_IF_FALSE (che era l’unica differenza tra di loro, oltre a utilizzare un diverso COMPARE_OP). Quando ho compilato il codice senza la ifs, ho ottenuto quello che ha ottenuto.
    • Un altro esempio in cui == e != non si escludono a vicenda è un SQL-like attuazione, con null valori. In SQL null non ritorno true per != rispetto a qualsiasi altro valore, in modo da python implementazioni di SQL interfacce possono anche avere lo stesso problema.
    • Sto cominciando a desiderare che non avevo menzionato l’eventuale differenza tra not == e !=, sembra essere la parte più interessante della mia risposta! Io non penso che questo sia il luogo per soffermarsi su di se, quando e perché che senso – si veda, ad esempio Perché Python hanno un __ne__ operatore metodo invece di __eq__?
  2. 29

    @jonrsharpe è un’ottima spiegazione di quello che sta succedendo. Ho pensato di mostrare solo la differenza di tempo quando l’esecuzione di ciascuna delle 3 opzioni di 10.000.000 di volte (abbastanza per una leggera differenza per mostrare).

    Codice:

    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)

    E il cProfile profiler risultati:

    Python se non == vs se !=

    In modo che possiamo vedere che c’è un minuto di differenza di ~0,7% tra if not x == 'val': e if x != 'val':. Di questi, if x != 'val': è il più veloce.

    Tuttavia, la maggior parte sorprendentemente, possiamo vedere che

    if x == 'val':
            pass
        else:

    è infatti il più veloce, e batte if x != 'val': da ~0.3%. Questo non è molto leggibile, ma credo che se si voleva un trascurabile miglioramento delle prestazioni, si potrebbe andare giù questo percorso.

    • Spero che tutti sanno non legge su questo tipo di informazioni! Rendendo illeggibili le modifiche 0,3% di miglioramento-o anche un miglioramento del 10% – è raramente una buona idea, e questo tipo di miglioramento, è molto probabile che sia evanescente (e non bene: molto lievi modifiche in Python runtime è in grado di eliminare o addirittura invertire qualsiasi guadagno.
    • In aggiunta, ci sono diverse implementazioni di Python.
  3. 6

    Nel primo Python per eseguire più operazioni rispetto al necessario(invece di solo il controllo non è uguale a deve controllare se non è vero che è uguale, quindi un’operazione più). Sarebbe impossibile dire la differenza da una esecuzione, ma se eseguito molte volte, la seconda sarebbe più efficiente. Nel complesso vorrei usare il secondo, ma matematicamente sono la stessa

  4. 5
    >>> 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

    Qui si può vedere che not x == y ha una istruzione di x != y. Quindi la differenza di prestazioni sarà molto piccolo nella maggior parte dei casi, a meno che si sta facendo milioni di confronto e anche allora questo potrebbe non essere la causa di un collo di bottiglia.

  5. 5

    Una nota aggiuntiva, dal momento che le altre risposte risposto alla tua domanda per lo più correttamente, è che se una classe definisce solo __eq__() e non __ne__(), allora il vostro COMPARE_OP (!=) verrà eseguito __eq__() e negarlo. A quel tempo, la terza opzione è probabile che sia un po ‘ più efficiente, ma deve essere considerato solo se hai BISOGNO di velocità, dal momento che è difficile da capire rapidamente.

  6. 3

    È circa il vostro modo di lettura. not operatore è dinamico, ecco perché sono in grado di applicare in

    if not x == 'val':

    Ma != si poteva leggere in un migliore contesto di un operatore che fa il contrario di ciò che == fa.

  7. 1

    Voglio approfondire la mia leggibilità commento di cui sopra.

    Di nuovo, sono completamente d’accordo con la leggibilità override altri (prestazioni trascurabile) preoccupazioni.

    Quello che vorrei sottolineare è che il cervello interpreta “positivo” più veloce di quanto non sia “negativo”. E. g., “stop” contro “non andare” (piuttosto pessimo esempio a causa della differenza nel numero di parole).

    Così data una scelta:

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

    è preferibile la funzionalmente equivalenti:

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

    Meno leggibilità/comprensione porta a ulteriori problemi. Forse non in iniziale di codifica, ma non intelligente come te!) le modifiche di manutenzione…

    • cervello interpreta “positivo” più veloce di quanto non faccia il “negativo” è questo per esperienza o hai letto gli studi su questo ? Sto solo chiedendo perché a seconda del codice (do) o (fare), trovo un != b più facile da capire.

Lascia un commento