Em Python, como devo testar se uma variável é None, True ou False

146

Eu tenho uma função que pode retornar uma das três coisas:

  • sucesso ( True)
  • falha ( False)
  • erro ao ler / analisar o fluxo ( None)

Minha pergunta é: se não devo testar contra Trueou False, como devo ver qual é o resultado. Abaixo está como eu estou fazendo isso atualmente:

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"

é realmente tão simples quanto remover a == Truepeça ou devo adicionar um tipo de dados tri-bool. Não quero que a simulatefunção gere uma exceção, pois tudo o que quero que o programa externo faça com um erro é registrá-lo e continuar.

James Brooks
fonte
Você está fazendo a pergunta errada; você deve estar pedindo ajuda para definir seu resultado ... qual é a diferença que você percebe entre "falha" e "fluxo de análise de erro", o que eles significam, quais são as conseqüências, qual ação o chamador provavelmente deseja executar em cada caso (aprovação, reprovação, erro de análise)?
John John Machin
Estou simulando um sistema de energia elétrica, se as pessoas perdem energia para suas casas, é um fracasso. Se não consigo ler o arquivo de simulação, isso é um erro de um tipo completamente diferente.
James Brooks
2
Dentro da simulatefunção, pego todas as exceções; Não quero que nada que aconteça dentro do simulador pare o restante do programa em execução (e processe o próximo elemento). Mas as respostas estão me fazendo mudar de idéia.
James Brooks
1
@ James Brooks: Certo. É disso que se trata o processo try / except. Se você simulatetem coisas que pode capturar e tentar novamente, isso é bom. Mas se "falhar", não deve retornar None. Deve apenas gerar uma exceção para o script que o chamou. De qualquer maneira, simulateestá feito. Retornar Nonenão é tão útil quanto gerar uma exceção adequada - ou permitir que uma exceção se propague simulateno script de chamada para manipulação.
precisa saber é o seguinte
1
@ James, use em except Exception:vez disso. Isso captura todos os erros "reais", junto com Warninge StopIteration. Permite KeyboardInterrupte SystemExitatravés de embora. Se você realmente deseja capturá-los, provavelmente é melhor usar outra tentativa / exceção externa ou alguma outra estrutura que documente claramente sua intenção, pois esses não são "erros". (Mas eu disse "quase nunca" ... talvez no seu caso você realmente queira pegar tudo, e até impedir que o Ctrl-C ou a sys.exit()saída, etc.) seja o que for
Peter #

Respostas:

119

Não tema a exceção! Ter seu programa apenas registrado e continuado é tão fácil quanto:

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

E agora você pode ter um tipo de notificação muito mais rico a partir do método simular sobre o que exatamente deu errado, caso você ache que erro / não erro não seja informativo o suficiente.

PaulMcG
fonte
Acordado. Muito mais pitônico do que a solução evidentemente mais popular acima (que cheira muito a código C).
Brandon
7
@Brandon Não acordado. Esse código é mais longo e, pior, menos legível que a solução acima (ou a versão aprimorada abaixo): mais indentações, mais declarações diferentes - adivinhe por que o último é mais popular, como você diz ... ;-) Por que tentar ser 'Pythonic' se isso leva a um código mais estranho ...?
Rolf Bartstra
Agora imprima o traceback em vez de "erro ao analisar o fluxo" e você recebeu meu voto.
21815 CivFan #
Ok, você conseguiu meu voto de qualquer maneira, mas eu quis dizer imprimir algo como traceback.format_exc() . Veja esta resposta SO.
CivFan
11
Muitas pessoas acessam esta página procurando a resposta para a pergunta do título. Para a maioria de nós "não tema a exceção!" não tem nada a ver com a nossa situação. Só precisamos testar True, False e None. Embora sua alternativa sugerida seja válida para alguns casos, acho melhor incluir também uma resposta à pergunta conforme ela foi solicitada.
vastlysuperiorman
162
if result is None:
    print "error parsing stream"
elif result:
    print "result pass"
else:
    print "result fail"

mantenha-o simples e explícito. É claro que você pode pré-definir um dicionário.

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

Se você planeja modificar sua simulatefunção para incluir mais códigos de retorno, a manutenção desse código pode se tornar um pouco problemática.

O simulatetambém pode gerar uma exceção no erro de análise, caso em que você quer iria pegá-lo aqui ou deixá-lo propagar um nível acima e o bit de impressão seria reduzida a uma linha com uma declaração if-else.

SilentGhost
fonte
1
O último é uma espécie de teste explícito contra Verdadeiro ou Falso, não é?
31410 Peter
1
é claro, mas sabendo que esses são apenas possíveis valores de retorno, não acho que seja um problema.
SilentGhost
e parecem ser um pouco mais rápido também
SilentGhost
a = 'foo' se um: print 'seu verdadeiro' um não é verdade, não é apenas nenhum
WESM
17

Nunca, nunca, nunca diga

if something == True:

Nunca. É uma loucura, já que você repete redundantemente o que é especificado redundantemente como a regra de condição redundante para uma instrução if.

Pior, ainda, nunca, nunca, nunca diga

if something == False:

Você tem not. Sinta-se livre para usá-lo.

Finalmente, fazer a == Noneé ineficiente. Faça a is None. Noneé um objeto singleton especial, só pode haver um. Basta verificar se você possui esse objeto.

S.Lott
fonte
3
Testar a igualdade com Truenão é redundante (embora eu concorde que não é sensato). Pode estar chamando um __eq__ou outro método especial, que pode fazer praticamente qualquer coisa.
Scott Griffiths
5
@ Scott Griffiths: Bom ponto. Esse é um cenário verdadeiramente e profundamente aterrorizante. Se esse for realmente o caso, o programa viola nossas expectativas fundamentais de uma maneira que torna algo que precisa ser simplesmente excluído e reescrito do zero sem essa magia negra.
S.Lott
78
'Nunca nunca nunca' ...? Há casos, porém, que if something == Trueproduzem um resultado diferente do que if something, por exemplo, para não-booleano something. 2==Trueproduz false enquanto 2avalia como true; None==Falseé falso, mas not Noneé verdade!
Rolf Bartstra
9
-1 Esta resposta é enganosa e completamente incorreta, pois o que @Rolf Bartstra diz é verdade. Embora neste caso, o que você diz pode ser aplicado.
HelloGoodbye 22/01
3
-1. Como qualquer valor diferente de zero ou não-vazio ou de comprimento zero para somethingretornos Truesobrebool(something) . Nesse caso, se você SOMENTE deseja verificar se somethingtem um valor de Trueie bool. Então você tem que fazer if something == TrueIMO.
Samarth Shah
2

Eu gostaria de enfatizar que, mesmo se houver situações em que if expr :não seja suficiente, porque se quer ter certeza de que expré Truee não apenas diferente de 0/ None/ seja o que for, isdeve ser preferida == pela mesma razão que S.Lott mencionou para evitar== None .

Na verdade, é um pouco mais eficiente e, mais fácil de entender, mais fácil de ler.

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)
Thrastylon
fonte
1
Você não pode executar uma referência uma vez e dizer que uma é mais eficiente que a outra (mesmo que seja). Execute-o muitas vezes (10.000) para ver como se comporta em média. \
user1767754
1

Acredito que lançar uma exceção é uma ideia melhor para a sua situação. Uma alternativa será o método de simulação para retornar uma tupla. O primeiro item será o status e o segundo o resultado:

result = simulate(open("myfile"))
if not result[0]:
  print "error parsing stream"
else:
  ret= result[1]
kgiannakakis
fonte
1
retornando tupla geralmente vai bem com desembalar uma tupla;)
SilentGhost
2
seu código, no entanto, não faz muito sentido; se Falsefor retornado, será impresso 'error parsing stream'.
SilentGhost
O método simular deve retornar (Falso, "qualquer coisa") ou (Verdadeiro, ret) onde ret é Falso ou Verdadeiro.
precisa saber é o seguinte
2
Bem, você está re-definindo os valores de saída de acordo com sua lógica, não é clara w / o uma explicação
SilentGhost