В 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

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


Согласовано. Намного более питонический, чем явно более популярное решение выше (которое слишком сильно пахнет кодом 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)

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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.