2010-08-20 6 views
11

Esiste una differenza di efficienza tra l'utilizzo e in un'istruzione if e l'utilizzo di più istruzioni if? In altre parole, è qualcosa di simileEfficienza Python di e contro più ifs

if expr1 == expr2 and expr3==expr4: 
    dostuff() 

diversa dal punto di vista dell'efficienza, allora:

if expr1 == expr2: 
    if expr3 == expr4: 
    dostuff() 

mio test molto semplice, non rivela una differenza, ma lo fa qualcuno con più conoscenza (o almeno più approfondita test) ha una risposta definitiva?

+1

http://stackoverflow.com/questions/2539116/python-if-statement-efficiency potrebbe essere correlato. – anijhaw

+1

Non conosco differenze con l'efficienza, ma ciò che dovrebbe essere più importante è la leggibilità del codice. Se è più chiaro usare più istruzioni "if" nidificate, allora fai ciò che pensi abbia senso. – derekerdmann

+1

Si dovrebbe guardare a questo nel disassemblatore se si vuole veramente sapere cosa sta succedendo, ma la prima espressione è altrettanto veloce (potenzialmente più veloce, ma probabilmente non ottimizzata in questo modo) perché Python utilizza la valutazione di cortocircuito. –

risposta

4

In entrambi i casi, expr1 == expr2 viene valutato su false in if, il secondo non verrà valutato.

14

Non è sufficiente una differenza di prestazioni, se presente, per influire sulla decisione. IMO, la decisione qui dovrebbe essere presa puramente da una prospettiva di leggibilità. Il primo è generalmente più standard, penso, ma ci sono situazioni in cui il secondo potrebbe essere più chiaro. Scegli il metodo che meglio riesce a ottenere il tuo intento.

+1

s/IMO //. È assolutamente folle scegliere uno di questi rispetto all'altro per motivi di prestazioni, in quasi ** qualsiasi ** lingua. Non c'è modo di quantificare quale sarà più veloce, l'implementazione può fare ciò che vuole. –

+1

Grazie.In generale, sono d'accordo e mi concentro sulla leggibilità rispetto all'efficienza. Ma in questo caso particolare, il se è in un ciclo che viene eseguito un numero considerevole di volte e ho il requisito di ridurre il tempo di esecuzione così, almeno questa volta potrebbe essere importante. – TimothyAWiseman

2

Il primo (uno if con and) è più veloce :-)

ho provato utilizzando timeit. Questi sono i risultati:

Variant 1: 9.82836714316 
Variant 2: 9.83886494559 
Variant 1 (True): 9.66493159804 
Variant 2 (True): 10.0392633241 

Per gli ultimi due, il primo confronto è True, quindi il secondo viene saltata. Risultati interessanti


import timeit 


print "Variant 1: %s" % timeit.timeit(""" 
for i in xrange(1000): 
    if i == 2*i and i == 3*i: 
     pass 
     """, 
     number = 1000) 

print "Variant 2: %s" % timeit.timeit(""" 
for i in xrange(1000): 
    if i == 2*i: 
     if i == 3*i: 
      pass 
     """, 
     number = 1000) 

print "Variant 1 (True): %s" % timeit.timeit(""" 
for i in xrange(1000): 
    if i == i and i == 3*i: 
     pass 
     """, 
     number = 1000) 

print "Variant 2 (True): %s" % timeit.timeit(""" 
for i in xrange(1000): 
    if i == i: 
     if i == 3*i: 
      pass 
     """, 
     number = 1000) 
10

Eventuali differenze di velocità tra l'uso and e if nidificati sarà minimo. Stai abbaiando sull'albero sbagliato. Considerate questo albero:

if oftenTrueCondition and rarelyTrueCondition: 

rispetto al

if rarelyTrueCondition and oftenTrueCondition: 

Quindi, a meno che la prima condizione deve essere valutata prima (è una guardia per fermare l'espressione successiva da crash o fare qualcosa di stupido/costoso), considera di scambiare l'ordine di valutazione.

+0

Un modo molto utile di pensare a ciò che non avevo considerato, e in realtà tornerà utile nel lavoro numerico. Grazie! –

3

In caso di dubbio, è possibile verificare che cosa pitone compilare le sue dichiarazioni in, utilizzando DIS modulo:

>>> import dis 
>>> def test1(): 
...  if expr1 == expr2 and expr3==expr4: 
...  dostuff() 
... 
>>> def test2(): 
...  if expr1 == expr2: 
...  if expr3 == expr4: 
...   dostuff() 
... 
>>> dis.dis(test1) 
    2   0 LOAD_GLOBAL    0 (expr1) 
       3 LOAD_GLOBAL    1 (expr2) 
       6 COMPARE_OP    2 (==) 
       9 JUMP_IF_FALSE   24 (to 36) 
      12 POP_TOP    
      13 LOAD_GLOBAL    2 (expr3) 
      16 LOAD_GLOBAL    3 (expr4) 
      19 COMPARE_OP    2 (==) 
      22 JUMP_IF_FALSE   11 (to 36) 
      25 POP_TOP    

    3   26 LOAD_GLOBAL    4 (dostuff) 
      29 CALL_FUNCTION   0 
      32 POP_TOP    
      33 JUMP_FORWARD    1 (to 37) 
     >> 36 POP_TOP    
     >> 37 LOAD_CONST    0 (None) 
      40 RETURN_VALUE   
>>> dis.dis(test2) 
    2   0 LOAD_GLOBAL    0 (expr1) 
       3 LOAD_GLOBAL    1 (expr2) 
       6 COMPARE_OP    2 (==) 
       9 JUMP_IF_FALSE   28 (to 40) 
      12 POP_TOP    

    3   13 LOAD_GLOBAL    2 (expr3) 
      16 LOAD_GLOBAL    3 (expr4) 
      19 COMPARE_OP    2 (==) 
      22 JUMP_IF_FALSE   11 (to 36) 
      25 POP_TOP    

    4   26 LOAD_GLOBAL    4 (dostuff) 
      29 CALL_FUNCTION   0 
      32 POP_TOP    
      33 JUMP_ABSOLUTE   41 
     >> 36 POP_TOP    
      37 JUMP_FORWARD    1 (to 41) 
     >> 40 POP_TOP    
     >> 41 LOAD_CONST    0 (None) 
      44 RETURN_VALUE   

Così come si può vedere, a livello di bytecode Python, entrambe le affermazioni sono gli stessi - anche mentre si utilizza singolo se alla prima istruzione, farà JUMP_IF_FALSE dopo il primo confronto.