En Python, ¿cómo debo probar si una variable es None, True o False?

146

Tengo una función que puede devolver una de tres cosas:

  • éxito ( True)
  • fracaso ( False)
  • error al leer / analizar secuencia ( None)

Mi pregunta es, si se supone que no debo hacer una prueba Trueo False, ¿cómo debo ver cuál es el resultado? A continuación se muestra cómo lo estoy haciendo actualmente:

result = simulate(open("myfile"))
if result == None:
    print "error parsing stream"
elif result == True: # shouldn't do this
    print "result pass"
else:
    print "result fail"

¿es realmente tan simple como eliminar la == Trueparte o debo agregar un tipo de datos tri-bool? No quiero que la simulatefunción arroje una excepción, ya que todo lo que quiero que haga el programa externo con un error es registrarlo y continuar.

James Brooks
fuente
Estás haciendo la pregunta equivocada; debe pedir ayuda para definir su resultado ... cuál es la diferencia que percibe entre "falla" y "secuencia de análisis de errores", qué significan, cuáles son las consecuencias, qué acción es probable que la persona que llama quiera tomar en cada caso (pasa, falla, error de análisis)?
John Machin
Estoy simulando un sistema de energía eléctrica, si las personas pierden energía en sus casas, es un fracaso. Si no puedo leer el archivo de simulación, entonces es un error de un tipo completamente diferente.
James Brooks el
2
Dentro de la simulatefunción capto todas las excepciones; No quiero que ocurra nada dentro del simulador para detener el resto del programa en ejecución (y procesar el siguiente elemento). Pero las respuestas me están haciendo cambiar de opinión.
James Brooks el
1
@ James Brooks: Correcto. De eso se trata el procesamiento de prueba / excepción. Si simulatetiene cosas que puede atrapar y volver a intentar, está bien. Pero si "falla", no debería volver None. Simplemente debería generar una excepción al script que lo llamó. De cualquier manera, simulateestá hecho. Volver Noneno es tan útil como generar una excepción adecuada, o permitir que una excepción se propague a través simulatedel script de llamada para su manejo.
S.Lott
1
@ James, use except Exception:en su lugar. Esto detecta todos los errores "reales", junto con Warningy StopIteration. Sin embargo, permite KeyboardInterrupty a SystemExittravés. Si realmente quiere atraparlos, probablemente sea mejor usar otro try / except externo o alguna otra estructura que documente claramente su intención, ya que esos no son "errores". (Pero dije "casi nunca" ... tal vez en su caso realmente quiera agarrar todo, e incluso evitar que Ctrl-C o sys.exit()salir, etc.)
Peter Hansen

Respuestas:

119

¡No temas a la excepción! Hacer que su programa solo inicie sesión y continúe es tan fácil como:

try:
    result = simulate(open("myfile"))
except SimulationException as sim_exc:
    print "error parsing stream", sim_exc
else:
    if result:
        print "result pass"
    else:
        print "result fail"

# execution continues from here, regardless of exception or not

Y ahora puede tener un tipo de notificación mucho más rico del método de simulación en cuanto a qué salió mal exactamente, en caso de que encuentre error / no-error que no sea lo suficientemente informativo.

PaulMcG
fuente
Convenido. Mucho más pitónico que la solución evidentemente más popular anterior (que huele demasiado a código C).
Brandon
77
@ Brandon No estoy de acuerdo. Este código es más largo y, lo que es peor, menos legible que la solución anterior (o la versión mejorada a continuación): más sangrías, más declaraciones diferentes: adivina por qué esta última es más popular, como dices ... ;-) ¿Por qué intentar ser 'Pythonic' si eso lleva a un código más incómodo ...?
Rolf Bartstra
Ahora imprima el rastreo en lugar de "flujo de análisis de error" y obtuvo mi voto.
CivFan
Ok, tienes mi voto de todos modos, pero yo quería decir algo de impresión como traceback.format_exc() . Ver esta respuesta SO.
CivFan
11
Muchas personas vendrán a esta página buscando la respuesta a la pregunta del título. Para la mayoría de nosotros "¡No temas a la excepción!" No tiene nada que ver con nuestra situación. Solo necesitamos probar Verdadero, Falso y Ninguno. Si bien su alternativa sugerida es válida para algunos casos, creo que es mejor incluir también una respuesta a la pregunta tal como fue formulada.
vastlysuperiorman
162
if result is None:
    print "error parsing stream"
elif result:
    print "result pass"
else:
    print "result fail"

manténgalo simple y explícito. Por supuesto, puede predefinir un diccionario.

messages = {None: 'error', True: 'pass', False: 'fail'}
print messages[result]

Si planea modificar su simulatefunción para incluir más códigos de retorno, mantener este código podría convertirse en un problema.

Es simulateposible que también genere una excepción en el error de análisis, en cuyo caso lo atraparía aquí o lo dejaría propagar un nivel superior y el bit de impresión se reduciría a una instrucción if-else de una línea.

SilentGhost
fuente
1
Este último es una especie de prueba explícita contra Verdadero o Falso, ¿no?
Peter Eisentraut
1
por supuesto, pero sabiendo que estos son solo valores de retorno posibles, no creo que sea un problema.
SilentGhost
y parece ser un poco más rápido también
SilentGhost
a = 'foo' si a: imprime 'su verdadero' a no es realmente VERDADERO, simplemente no es ninguno
wesm
17

Nunca, nunca, nunca digas

if something == True:

Nunca. Es una locura, ya que está repitiendo de forma redundante lo que se especifica de forma redundante como la regla de condición redundante para una declaración if.

Peor aún, nunca, nunca, nunca digas

if something == False:

Usted tiene not. Sientase libre de usarlo.

Finalmente, hacer a == Nonees ineficiente. Hacer a is None. Nonees un objeto singleton especial, solo puede haber uno. Solo verifique si tiene ese objeto.

S.Lott
fuente
3
Las pruebas de igualdad con Trueno son redundantes (aunque estoy de acuerdo en que no es razonable). Se podría llamar a una __eq__u otra método especial, lo que podría hacer prácticamente cualquier cosa.
Scott Griffiths
55
@Scott Griffiths: Buen punto. Ese es un escenario verdaderamente y profundamente horrible. Si ese es realmente el caso, el programa viola nuestras expectativas fundamentales de una manera que lo convierte en algo que simplemente debe eliminarse y reescribirse desde cero sin dicha magia negra.
S.Lott
78
'Nunca nunca nunca' ...? Sin embargo, hay casos que if something == Trueproducen un resultado diferente que if something, por ejemplo, para no booleanos something. 2==Trueproduce falsa mientras que 2se considera verdadero; None==Falsees falso pero not Nonees cierto!
Rolf Bartstra
9
-1 Esta respuesta es engañosa y completamente incorrecta, ya que lo que dice @Rolf Bartstra es cierto. Aunque en este caso, lo que dices se puede aplicar.
Hola
3
-1. Dado que cualquier valor distinto de cero o no vacía o no de longitud cero para somethingretornos Truesobre bool(something). En ese caso, si SOLO quiere comprobar si somethingtiene un valor de Trueie bool. Entonces tienes que hacer if something == TrueIMO.
Samarth Shah
2

Me gustaría hacer hincapié en que, aunque hay situaciones en que if expr :no es suficiente porque uno quiere asegurarse de que expres Truey no sólo diferente de 0/ None/ lo que sea, isha de ser preferido a partir == por la misma razón S. Lott mencionado para evitar== None .

De hecho, es un poco más eficiente y, cereza en el pastel, más legible para los humanos.

In [1]: %timeit (1 == 1) == True
38.1 ns ± 0.116 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [2]: %timeit (1 == 1) is True
33.7 ns ± 0.141 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
Trastylon
fuente
1
No puede ejecutar un punto de referencia una vez y decir que uno es más eficiente que el otro (aunque podría serlo). Ejecútelo muchas veces (10.000) para ver cómo se comporta en promedio. \
user1767754
1

Creo que lanzar una excepción es una mejor idea para su situación. Una alternativa será el método de simulación para devolver una tupla. El primer elemento será el estado y el segundo el resultado:

result = simulate(open("myfile"))
if not result[0]:
  print "error parsing stream"
else:
  ret= result[1]
kgiannakakis
fuente
1
regresar tupla generalmente va bien con desempacar una tupla;)
SilentGhost
2
su código, sin embargo, no tiene mucho sentido, si Falsese devuelve, se imprimirá 'error parsing stream'.
SilentGhost
El método de simulación debe devolver (Falso, "cualquier cosa") o (Verdadero, ret) donde ret es Falso o Verdadero.
kgiannakakis
2
bueno, está redefiniendo los valores de salida para adaptarse a su lógica, no está claro sin una explicación
SilentGhost