2009-04-15 7 views
46

¿Es una mala práctica usar el siguiente formato cuando my_var puede ser Ninguno?¿Es seguro confiar en la orden de evaluación de condición en las declaraciones if?

if my_var and 'something' in my_var: 
    #do something 

El tema es que 'something' in my_var arrojará un TypeError si my_var es Ninguno.

o debería utilizar:

if my_var: 
    if 'something' in my_var: 
     #do something 

o

try: 
    if 'something' in my_var: 
     #do something 
except TypeError: 
    pass 

reformular la pregunta, que de lo anterior es la mejor práctica en Python (si los hay)?

¡Las alternativas son bienvenidas!

Respuesta

64

Es seguro depender del orden de los condicionales (Python reference here), específicamente por el problema que usted señala: es muy útil poder realizar un cortocircuito de evaluación que podría causar problemas en una serie de condicionales.

Este tipo de código aparece en la mayoría de idiomas:

IF exists(variable) AND variable.doSomething() 
    THEN ... 
+2

Cuando veo un código como el segundo, supongo que el codificador no entendió cómo funciona la evaluación de cortocircuito. – Dana

+1

-1: Sin citas de la documentación: http://docs.python.org/library/stdtypes.html#boolean-operations-and-or-not –

+0

@cfi: Como puedo cambiar mi voto después de que la respuesta cambia, No estoy seguro de cuál es el problema. –

1

es perfectamente seguro y lo hago todo el tiempo.

1

Me gustaría ir con el try/except, pero depende de lo que sepa sobre la variable.

Si espera que la variable exista la mayor parte del tiempo, entonces try/except es menos operaciones. Si espera que la variable sea None la mayor parte del tiempo, una instrucción IF será menos operaciones.

+0

¿por qué (legibilidad, rendimiento, etc.)? – tgray

+0

He actualizado la respuesta –

27

Sí que es seguro, es muy explícita y claramente definido en la referencia del lenguaje:

La expresión x and y evalúa primero x; si x es false, su valor es devuelto; de lo contrario, y se evalúa y se devuelve el valor resultante.

La expresión x or y primero evalúa x; si x es verdadero, su valor es devuelto; de lo contrario, y se evalúa y se devuelve el valor resultante.

+1

Débil: no es "seguro" - es absolutamente necesario depender del pedido. –

1

No es tan simple. Como tío C#, estoy muy acostumbrado a hacer algo como:

if(x != null && ! string.isnullorempty(x.Name)) 
{ 
    //do something 
} 

Lo anterior funciona muy bien y se evalúa como se espera. Sin embargo en VB.Net la siguiente produciría un resultado que no esperábamos:

If Not x Is Nothing **And** Not String.IsNullOrEmpty(x.Name) Then 

    'do something 

End If 

Lo anterior generará una excepción.La sintaxis correcta debe ser

If Not x Is Nothing **AndAlso** Not String.IsNullOrEmpty(x.Name) Then 

    'do something 

End If 

Tenga en cuenta la diferencia muy sutil. Esto me confundió durante unos 10 minutos (demasiado tiempo) y es por eso que C# (y otros) tipos deben tener mucho cuidado al codificar en otros idiomas.

2

yo esté siendo un poco pedante aquí, pero yo diría que la mejor respuesta es

if my_var is not None and 'something' in my_var: 
    #do something 

La diferencia es la comprobación explícita para None, en lugar de la conversión implícita de my_var-True o False.

Aunque estoy seguro de que en su caso la distinción no es importante, en el caso más general, sería muy posible que la variable que no sea None pero aún evaluar a False, por ejemplo, un valor entero de 0 o una lista vacía

Así que, contrariamente a la mayoría de las afirmaciones de otros carteles de que es seguro, yo diría que es seguro siempre y cuando seas explícito. Si no está convencido y luego considerar esta clase muy artificial:

class Contrived(object): 
    def __contains__(self, s): 
     return True 
    def __nonzero__(self): 
     return False 

my_var = Contrived() 
if 'something' in my_var: 
    print "Yes the condition is true" 
if my_var and 'something' in my_var: 
    print "But this statement won't get reached." 
if my_var is not None and 'something' in my_var: 
    print "Whereas this one will." 

Sí, sé que no es un ejemplo realista, pero las variaciones ocurren en el código real, especialmente cuando None se utiliza para indicar un argumento de función por defecto.

+0

seguramente, si tiene una lista vacía o cualquier contenedor, para el caso, hacer la operación 'in' no tiene sentido. Creo que OP lo tiene exactamente correcto. si bien es posible construir algo para probar el punto, no creo que ningún código decente se pegue un tiro en el pie. – SilentGhost

+1

Sí, es un ejemplo inventado, pero mi punto principal es que es fácil caer en el mal hábito de decir "si var" cuando realmente quiere decir "si var no es ninguno". Una vez que te metes en ese hábito, puede morderte fácilmente, particularmente con argumentos incumplidos. –

+0

Creo que está bastante claro que la intención de OP era decir 'si var' y eso es lo que hizo. – SilentGhost

Cuestiones relacionadas