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.


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.


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.


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.


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)

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]

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.