У Python як слід перевірити, чи змінною немає None, True чи False


147

У мене є функція, яка може повернути одну з трьох речей:

  • успіх ( 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частину чи слід додати тип даних трибулевого типу. Я не хочу, щоб simulateфункція кидала виняток, оскільки все, що я хочу, щоб зовнішня програма робила помилку - це занотувати її та продовжувати.


Ви ставите неправильне запитання; вам слід попросити допомогу з визначенням вашого результату ... у чому різниця, яку ви сприймаєте між "невдачею" та "потоком розбору помилок", що вони означають, які наслідки, які дії може викликати абонент. у кожному випадку (помилка пропуску, помилка, розбір)?
Джон Махін

Я симулюю електроенергетичну систему, якщо люди втрачають живлення в своїх будинках, це несправність. Якщо я не можу прочитати файл симуляції, то це помилка зовсім іншого типу.
Джеймс Брукс

2
Всередині simulateфункції я вловлюю всі винятки; Я не хочу, щоб все, що відбувається всередині симулятора, зупиняло роботу всієї програми (та обробку наступного елемента). Але відповіді змушують мене змінити свою думку.
Джеймс Брукс

1
@James Brooks: Правильно. Це те, про що йдеться / окрім обробки. Якщо у вас simulateє речі, які він може зловити і повторити, це добре. Але якщо вона "провалюється", вона не повинна повертатися None. Він повинен просто створити виняток із сценарію, який його назвав. Так чи інакше, simulateробиться. Повернення Noneне є настільки корисним, як підняття належного винятку - або дозволити розповсюдженню виключення simulateв сценарій виклику для обробки.
S.Lott

1
@James, використовуйте except Exception:замість цього. Це фіксує всі "реальні" помилки, разом із Warningта StopIteration. Це дозволяє KeyboardInterruptі SystemExitчерез те, хоча. Якщо ви дійсно хочете їх впіймати, можливо, найкраще скористатися іншою, зовнішньою спробою / за винятком або якоюсь іншою структурою, яка чітко документує ваш намір, оскільки це не "помилки". (Але я сказав "майже ніколи" ... можливо, у вашому випадку ви дійсно хочете схопити все, і навіть завадите Ctrl-C або sys.exit()вийти, і т. Д.)
Пітер Хансен

Відповіді:


119

Не бійтеся винятку! Запропонувати програму просто увійти та продовжити так само просто:

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

Тепер ви можете отримати набагато багатший тип сповіщення від методу моделювання щодо того, що саме пішло не так, якщо ви виявите, що помилка / помилка не є достатньо інформативною.


Домовились. Набагато пітонічніше, ніж очевидно більш популярне рішення вгорі (яке занадто пахне кодом С).
Брендон

7
@Brandon Не погоджено. Цей код довший і, що ще гірше, менш читабельний, ніж рішення вище (або вдосконалена версія нижче): більше відступів, більше різних тверджень - здогадайтесь, чому останній є більш популярним, як ви кажете ... ;-) Чому намагаються бути "Пітонічний", якщо це призводить до більш незручного коду ...?
Рольф Бартстра

Тепер надрукуйте прослідкування замість "потоку розбору помилок", і ви отримали мій голос.
CivFan

Гаразд, ти все одно отримав мій голос, але я мав на увазі надрукувати щось на кшталт traceback.format_exc() . Дивіться цю відповідь ТАК.
CivFan

11
Багато людей завітають на цю сторінку, шукаючи відповідь на заголовне питання. Для більшості з нас "Не бійтеся винятку!" не має нічого спільного з нашою ситуацією. Нам просто потрібно перевірити на True, False та None. Хоча запропонована нами альтернатива є дійсною для деяких випадків, я думаю, що найкраще також включити відповідь на запитання, яке було задано.
надзвичайно суперіорман

163
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
Останнє є своєрідним явним тестом на Істинне чи Невірне, чи не так?
Пітер Ейзентраут

1
Звичайно, але знаючи, що це лише можливі повернені значення, я не думаю, що це проблема.
SilentGhost

і здається, це теж трохи швидше
SilentGhost

a = 'foo', якщо a: надрукувати 'його справжнє' a насправді не є ПРАВИЛЬНИМ, це просто не так
wesm

17

Ніколи, ніколи, ніколи не кажи

if something == True:

Ніколи. Це божевільно, оскільки ви надмірно повторюєте те, що надмірно вказано як правило надлишкової умови для заяви-if.

Гірше, все-таки, ніколи, ніколи, ніколи не кажіть

if something == False:

У вас є not. Сміливо користуйтеся ним.

Нарешті, робити a == Noneце неефективно. Зробіть a is None. Noneє спеціальним однотонним об'єктом, може бути лише один. Просто перевірте, чи є у вас цей об’єкт.


3
Тестування на рівність із Trueне зайвим (хоча я згоден, це нерозумно). Це може бути виклик того __eq__чи іншого спеціального методу, який міг зробити практично все.
Скотт Гріффітс

5
@Scott Griffiths: Добре. Це справді і дуже жахливий сценарій. Якщо це насправді так, програма порушує наші фундаментальні очікування таким чином, що це робить щось, що потрібно просто видалити і переписати з нуля без такої чорної магії.
S.Lott

78
"Ніколи, ніколи, ніколи" ...? Хоча є випадки, які 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має значення Trueтобто bool. Тоді ВИ МАЄТЕ робити if something == TrueІМО.
Самарт Шах

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

1

Я вважаю, що кидати виняток - це краща ідея для вашої ситуації. Альтернативою буде метод моделювання повернення кортежу. Перший елемент буде статусом, а другий - результатом:

result = simulate(open("myfile"))
if not result[0]:
  print "error parsing stream"
else:
  ret= result[1]

1
повернення кортежу зазвичай добре поєднується з розпакуванням кортежу;)
SilentGhost

2
ваш код, однак, не має особливого сенсу, якщо Falseйого повернуть, він надрукується 'error parsing stream'.
SilentGhost

Метод імітації повинен повертатися (False, "взагалі що-небудь") або (True, ret), де ret є хибним або істинним.
kgiannakakis

2
добре, ви переосмислюєте вихідні значення, щоб відповідати вашій логіці, незрозуміло без пояснень
SilentGhost
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.