В Python, как мне проверить, является ли переменная None, True или False

156

У меня есть функция, которая может возвращать одно из трех:

  • успех ( True)
  • сбой ( False)
  • ошибка чтения / анализа потока ( None)

У меня вопрос, если я не должен тестировать против Trueили False, как мне увидеть результат. Вот как я сейчас это делаю:

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"

действительно ли это так же просто, как удаление == Trueчасти, или я должен добавить тип данных tri-bool. Я не хочу, чтобы simulateфункция генерировала исключение, поскольку все, что я хочу, чтобы внешняя программа делала с ошибкой, - это регистрировать ее и продолжать.

Джеймс Брукс
источник
Вы задаете неправильный вопрос; вам следует попросить помощи в определении вашего результата ... в чем разница, которую вы воспринимаете между "неудачей" и "потоком анализа ошибок", что они означают, каковы последствия, какое действие вызывающий, вероятно, захочет предпринять в каждом случае (пройден, не пройден, ошибка разбора)?
Джон Мачин
Я моделирую систему электроснабжения, если люди теряют электроэнергию в своих домах, это неисправность. Если я не могу прочитать файл симуляции, значит, это ошибка совершенно другого рода.
Джеймс Брукс
2
Внутри simulateфункции я ловлю все исключения; Я не хочу, чтобы что-либо, происходящее внутри симулятора, останавливало выполнение остальной части программы (и обработку следующего элемента). Но ответы заставляют меня изменить свое мнение.
Джеймс Брукс
1
@ Джеймс Брукс: Верно. Вот в чем суть обработки try / except. Если у вас simulateесть что-то, что он может поймать и повторить, это хорошо. Но если он «проваливается», он не должен возвращаться None. Он должен просто вызвать исключение для сценария, который его вызвал. В любом случае simulateготово. Возврат Noneне так полезен, как создание правильного исключения - или разрешение исключения распространяться simulateв вызывающий скрипт для обработки.
S.Lott
1
@James, используйте except Exception:вместо этого. Это перехватывает все "настоящие" ошибки вместе с Warningи StopIteration. Это позволяет KeyboardInterruptи SystemExitнасквозь. Если вы действительно хотите их поймать, вероятно, лучше всего использовать другую, внешнюю try / except или какую-то другую структуру, которая четко документирует ваше намерение, поскольку это не «ошибки». (Но я сказал «почти никогда» ... возможно, в вашем случае вы действительно хотите захватить все и даже предотвратить Ctrl-C или sys.exit()выход и т. Д.)
Питер Хансен

Ответы:

121

Не бойтесь исключения! Заставить вашу программу просто войти и продолжить - это так же просто, как:

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

И теперь у вас может быть гораздо более богатый тип уведомления от метода моделирования о том, что именно пошло не так, если вы обнаружите, что ошибка / отсутствие ошибки недостаточно информативны.

PaulMcG
источник
Согласовано. Намного более питонический, чем явно более популярное решение выше (которое слишком сильно пахнет кодом C).
Брэндон
8
@Brandon Не согласен. Этот код длиннее и, что еще хуже, менее читабелен, чем решение выше (или улучшенная версия ниже): больше отступов, больше разных операторов - угадайте, почему последний, как вы говорите, более популярен ... ;-) Зачем пытаться быть "Pythonic", если это приведет к более неудобному коду ...?
Рольф Бартстра 06
Теперь распечатайте трассировку вместо «поток анализа ошибок», и вы получите мой голос.
CivFan
Хорошо, ты все равно получил мой голос, но я имел в виду напечатать что-то вроде traceback.format_exc() . См. Этот ТАК ответ.
CivFan
17
Многие люди будут заходить на эту страницу в поисках ответа на заглавный вопрос. Для большинства из нас «Не бойтесь исключения!» не имеет ничего общего с нашей ситуацией. Нам просто нужно проверить True, False и None. Хотя предложенная вами альтернатива действительна для некоторых случаев, я думаю, что лучше также включить ответ на вопрос, который был задан.
superiorman
176
if result is None:
    print "error parsing stream"
elif result:
    print "result pass"
else:
    print "result fail"

сделайте это простым и ясным. Конечно, вы можете заранее определить словарь.

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

Если вы планируете изменить свою simulateфункцию, чтобы включить больше кодов возврата, сохранение этого кода может стать проблемой.

Это simulateтакже может вызвать исключение при ошибке синтаксического анализа, и в этом случае вы либо поймаете его здесь, либо позволите ему распространиться на уровень выше, и бит печати будет уменьшен до однострочного оператора if-else.

Тихий призрак
источник
1
Последнее является своего рода явным тестом на True или False, не так ли?
Питер Эйзентраут
1
конечно, но зная, что это только возможные возвращаемые значения, я не думаю, что это проблема.
SilentGhost 07
и вроде бы немного быстрее
SilentGhost
a = 'foo', если a: print 'its true' a на самом деле не TRUE, это просто не none
wesm
и только не Ложь
00schneider
14

Никогда, никогда, никогда не говори

if something == True:

Никогда. Это безумие, поскольку вы повторно повторяете то, что избыточно указано как правило избыточного условия для оператора if.

Хуже того, никогда, никогда, никогда не говори

if something == False:

У тебя есть not. Не стесняйтесь использовать это.

Наконец, делать a == Noneэто неэффективно. Делай a is None. Noneэто особый одноэлементный объект, может быть только один. Просто проверьте, есть ли у вас этот объект.

С.Лотт
источник
3
Проверка на равенство с Trueне является избыточной (хотя я согласен, что это нецелесообразно). Это может быть вызов какого- __eq__либо специального метода, который может делать практически все.
Скотт Гриффитс
5
@ Скотт Гриффитс: Хорошая мысль. Это действительно ужасающий сценарий. Если это действительно так, программа нарушает наши фундаментальные ожидания, делая ее чем-то, что нужно просто удалить и переписать с нуля без такой черной магии.
S.Lott
84
'Никогда никогда никогда' ...? Однако бывают случаи, if something == Trueкогда результат отличается от if something, например, для небулева something. 2==Trueдает ложь, тогда как 2оценивается как истина; None==Falseложно, но not Noneверно!
Рольф Бартстра
9
-1 Этот ответ вводит в заблуждение и совершенно неверен, поскольку то, что говорит @Rolf Bartstra, правда. Хотя в данном случае, что вы говорите , может быть применен.
HelloGoodbye
3
-1. Так как любой ненулевой или непустой или не нулевой длины значения для somethingвозвращения Trueна bool(something). В этом случае, если вы хотите ТОЛЬКО проверить, somethingимеет ли значение Trueie bool. Тогда вы ДОЛЖНЫ сделать if something == TrueИМО.
Samarth Shah
2

Я хотел бы подчеркнуть, что, даже если есть ситуации, когда if expr :этого недостаточно, потому что нужно убедиться, что он exprесть, Trueа не просто отличается от 0/ None/ чего-то еще, isследует предпочесть == по той же причине, по которой С.Лотт упомянул, что он избегает== None .

Это действительно немного более эффективно и, главное, удобочитаемо.

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
источник
1
Вы не можете запустить тест один раз и сказать, что один более эффективен, чем другой (даже если это может быть). Запустите его много раз (10.000), чтобы увидеть, как он ведет себя в среднем. \
user1767754 01
2

Есть много хороших ответов. Хочу добавить еще один момент. Ошибка может попасть в ваш код, если вы работаете с числовыми значениями, и ваш ответ оказался 0.

a = 0 
b = 10 
c = None

### Common approach that can cause a problem

if not a:
    print(f"Answer is not found. Answer is {str(a)}.") 
else:
    print(f"Answer is: {str(a)}.")

if not b:
    print(f"Answer is not found. Answer is {str(b)}.") 
else:
    print(f"Answer is: {str(b)}")

if not c:
    print(f"Answer is not found. Answer is {str(c)}.") 
else:
    print(f"Answer is: {str(c)}.")
Answer is not found. Answer is 0.   
Answer is: 10.   
Answer is not found. Answer is None.
### Safer approach 
if a is None:
    print(f"Answer is not found. Answer is {str(a)}.") 
else:
    print(f"Answer is: {str(a)}.")

if b is None:
    print(f"Answer is not found. Answer is {str(b)}.") 
else:
    print(f"Answer is: {str(b)}.")

if c is None:
    print(f"Answer is not found. Answer is {str(c)}.") 
else:
    print(f"Answer is: {str(c)}.")

Answer is: 0.
Answer is: 10.
Answer is not found. Answer is None.
Наим Хошневис
источник
1

Я считаю, что создание исключения - лучшая идея для вашей ситуации. Альтернативой будет метод моделирования для возврата кортежа. Первый элемент будет статусом, а второй - результатом:

result = simulate(open("myfile"))
if not result[0]:
  print "error parsing stream"
else:
  ret= result[1]
Кгианнакакис
источник
1
возврат кортежа обычно хорошо сочетается с распаковкой кортежа;)
SilentGhost 07
2
ваш код, однако, не имеет особого смысла, если он Falseбудет возвращен, он напечатает 'error parsing stream'.
SilentGhost 07
Метод моделирования должен возвращать (False, «что угодно») или (True, ret), где ret имеет значение False или True.
kgiannakakis 07
2
ну, вы переопределяете выходные значения в соответствии со своей логикой, это неясно без объяснения
SilentGhost