print float python if-statement equality

float - python string format replace



Python si no== vs if!= (7)

¿Cuál es la diferencia entre estas dos líneas de código?

if not x == ''val'':

y

if x != ''val'':

¿Es uno más eficiente que el otro?

¿Sería mejor usar

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


@jonrsharpe tiene una excelente explicación de lo que está sucediendo. Pensé que solo mostraría la diferencia en el tiempo al ejecutar cada una de las 3 opciones 10,000,000 de veces (suficiente para mostrar una ligera diferencia).

Código usado:

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)

Y los resultados del perfilador cProfile:

Entonces podemos ver que hay una diferencia muy pequeña de ~ 0.7% entre if not x == ''val'': y if x != ''val'': De estos, if x != ''val'': es el más rápido.

Sin embargo, lo más sorprendente es que podemos ver que

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

es, de hecho, el más rápido, y late if x != ''val'': en ~ 0.3%. Esto no es muy legible, pero supongo que si quisieras una mejora insignificante del rendimiento, uno podría seguir esta ruta.


En el primero, Python tiene que ejecutar una operación más de la necesaria (en lugar de simplemente verificar que no sea igual, tiene que verificar si no es cierto que sea igual, por lo tanto, una operación más). Sería imposible distinguir la diferencia de una ejecución, pero si se ejecuta muchas veces, la segunda sería más eficiente. En general, usaría el segundo, pero matemáticamente son lo mismo


Quiero ampliar mi comentario de legibilidad anterior.

Nuevamente, estoy completamente de acuerdo con la legibilidad que anula otras preocupaciones (insignificantes en cuanto al rendimiento).

Lo que me gustaría señalar es que el cerebro interpreta "positivo" más rápido que "negativo". Por ejemplo, "parar" frente a "no ir" (un ejemplo bastante pésimo debido a la diferencia en el número de palabras).

Entonces, dado una opción:

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

es preferible al equivalente funcional:

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

Menos legibilidad / comprensibilidad conduce a más errores. Quizás no en la codificación inicial, pero el mantenimiento (¡no tan inteligente como usted!) Cambia ...


Se trata de tu forma de leerlo. not operador es dinámico, es por eso que puede aplicarlo en

if not x == ''val'':

Pero != Podría leerse en un mejor contexto como un operador que hace lo contrario de lo que == hace.


Una nota adicional, dado que las otras respuestas respondieron su pregunta en su mayoría correctamente, es que si una clase solo define __eq__() y no __ne__() , entonces COMPARE_OP (!=) Ejecutará __eq__() y lo __eq__() . En ese momento, es probable que su tercera opción sea un poco más eficiente, pero solo debe considerarse si NECESITA la velocidad, ya que es difícil de entender rápidamente.


Usando dis para mirar el bytecode generado para las dos versiones:

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

Este último tiene menos operaciones y, por lo tanto, es probable que sea un poco más eficiente.

Se señaló en los comentarios (gracias, @Quincunx ) que donde tienes if foo != bar vs. if not foo == bar el número de operaciones es exactamente el mismo, es solo que COMPARE_OP cambia y POP_JUMP_IF_TRUE cambia 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

En este caso, a menos que haya una diferencia en la cantidad de trabajo requerido para cada comparación, es poco probable que vea alguna diferencia de rendimiento.

Sin embargo, tenga en cuenta que las dos versiones no siempre serán lógicamente idénticas , ya que dependerá de las implementaciones de __eq__ y __ne__ para los objetos en cuestión. Según la documentación del modelo de datos :

No hay relaciones implícitas entre los operadores de comparación. La verdad de x==y no implica que x!=y sea ​​falso.

Por ejemplo:

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

Finalmente, y quizás lo más importante: en general, donde los dos son lógicamente idénticos, x != y es mucho más legible que not x == y .


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

Aquí puede ver que not x == y tiene una instrucción más que x != y Por lo tanto, la diferencia de rendimiento será muy pequeña en la mayoría de los casos, a menos que esté haciendo millones de comparaciones e incluso entonces esto probablemente no sea la causa de un cuello de botella.