2010-08-20 19 views
11

¿Existe una diferencia de eficiencia entre usar y en una sentencia if y usar múltiples sentencias if? En otras palabras, es algo así comoEficiencia de Python de y frente a múltiples ifs

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

diferente de una perspectiva de la eficiencia a continuación:

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

Mi prueba muy básico no revela una diferencia, pero lo hace alguien con más conocimiento (o al menos más a fondo prueba) tienen una respuesta definitiva?

+1

http://stackoverflow.com/questions/2539116/python-if-statement-efficiency puede estar relacionado. – anijhaw

+1

No conozco ninguna diferencia con la eficiencia, pero lo que debería ser más importante es la legibilidad de su código. Si es más claro utilizar múltiples declaraciones 'if' anidadas, entonces haz lo que creas que tenga sentido. – derekerdmann

+1

Debería ver esto en el desensamblador si realmente quiere saber qué está sucediendo, pero la primera expresión es igual de rápida (potencialmente más rápida, pero probablemente no optimizada de esa manera) porque Python utiliza la evaluación de cortocircuito. –

Respuesta

4

En cualquier caso, expr1 == expr2 evalúa a false en if, el segundo no será evaluado.

14

Esto no es suficiente una diferencia de rendimiento, si corresponde, para afectar su decisión. OMI, la decisión aquí debe tomarse puramente desde una perspectiva de legibilidad. El primero es generalmente más estándar, creo, pero hay situaciones en las que el segundo podría ser más claro. Elija el método que mejor convenga a su intención.

+1

s/IMO //. Es una locura elegir uno de estos sobre el otro por motivos de rendimiento, en casi cualquier idioma **. No hay forma de cuantificar cuál será más rápido, la implementación puede hacer lo que quiera. –

+1

Gracias.Generalmente, estoy de acuerdo y me concentro en la legibilidad sobre la eficiencia. Pero en este caso particular, el if se está ejecutando en un bucle una cantidad considerable de veces y tengo un requerimiento para reducir el tiempo de ejecución así que, al menos esta vez podría ser importante. – TimothyAWiseman

2

El primero de ellos (uno con ifand) es más rápido :-)

lo probé usando timeit. Estos son los resultados:

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

Para los dos últimos, la primera comparación es True, por lo que la segunda se omite. Resultados interesantes


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

Cualquier diferencia en velocidad entre el uso de and y ifs anidados serán mínimos. Estás ladrando al árbol equivocado. Considere este árbol:

if oftenTrueCondition and rarelyTrueCondition: 

en comparación con

if rarelyTrueCondition and oftenTrueCondition: 

Por lo tanto, a menos que la primera condición debe ser evaluado primero (que es un guardia para detener la siguiente expresión se estrelle o hacer algo tonto/caro), considere intercambiar el orden de la evaluación.

+0

Una manera muy útil de pensar sobre esto que no había considerado, y de hecho será útil en el trabajo numérico. ¡Gracias! –

3

En caso de duda, se puede comprobar lo que se compila pitón sus declaraciones en, utilizando dis módulo:

>>> 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   

Así como se puede ver, a nivel pitón código de bytes, ambas declaraciones son los mismos - incluso mientras se utiliza declaración única si al principio, hará JUMP_IF_FALSE después de la primera comparación.

Cuestiones relacionadas