Как назначить недостижимый код python

Какой питонический способ обозначить недостижимый код в python, как в:

gender = readFromDB(...) # either 'm' or 'f'
if gender == 'm':
    greeting = 'Mr.'
elif gender == 'f':
    greeting = 'Ms.'
else:
    # What should this line say?

Ответ 1

raise ValueError('invalid gender %r' % gender)

Ответ 2

Это зависит от того, насколько вы уверены в том, что пол имеет значение 'm' или 'f'.

Если вы абсолютно уверены, используйте if...else вместо if...elif...else. Просто облегчает для всех.

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

Ответ 3

Вы можете создать исключение:

raise ValueError("Unexpected gender; expected 'm' or 'f', got %s" % gender)

или используйте assert False, если вы ожидаете, что база данных вернет только "m" или "f":

assert False, "Unexpected gender; expected 'm' or 'f', got %s" % gender

Ответ 4

Я действительно думаю, что есть место для этого.

class SeriousDesignError( Exception ):
    pass

Итак, вы можете сделать это

if number % 2 == 0:
    result = "Even"
elif number % 2 == 1:
    result = "Odd"
else:
    raise SeriousDesignError()

Я думаю, что это наиболее значимое сообщение об ошибке. Такие вещи могут возникать только из-за ошибок дизайна (или плохого обслуживания, что является одним и тем же.)

Ответ 5

Это зависит от того, что вы хотите сообщить об ошибке, но я бы использовал словарь в этом случае:

greetings={'m':'Mr.', 'f':'Ms.'}
gender = readFromDB(...) # either 'm' or 'f'
greeting=greetings[gender]

Если пол не является ни m, ни f, это приведет к увеличению KeyError, содержащему неожиданное значение:

greetings={'m':'Mr.', 'f':'Ms.'}

>>> greetings['W']

Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
    greetings['W']
KeyError: 'W'

Если вы хотите получить больше подробностей в сообщении, вы можете поймать и сделать ререйз:

try:
  greeting = greetings[gender]
except KeyError,e:
  raise ValueError('Unrecognized gender %s'%gender)

Ответ 6

До сих пор я обычно использовал вариацию ответа Джона Фухи - но это не совсем правильно, как указывает Итан:

assert gender in ('m', 'f')
if gender == 'm':
    greeting = 'Mr.'
else:
    greeting = 'Ms.'

Основная проблема с использованием assert заключается в том, что если кто-то запускает ваш код с помощью флагов -O или -OO, утверждения будут оптимизированы. Как указывает Итан ниже, это означает, что теперь у вас нет проверок данных вообще. Утверждения являются вспомогательным средством развития и не должны использоваться для производственной логики. Вместо этого я привык использовать функцию check() - это позволяет использовать чистый синтаксис вызова, например assert:

def check(condition, msg=None):
    if not condition:
        raise ValueError(msg or '')

check(gender in ('m', 'f'))
if gender == 'm':
    greeting = 'Mr.'
else:
    greeting = 'Ms.'

Возвращаясь к исходному вопросу, я бы сказал, что использование функции assert() или check() перед логикой if/else легче читать, безопаснее и более явным:

  • он сначала проверяет качество данных, прежде чем приступать к нему, - это может быть важно, если в цепочке if/else есть операторы, отличные от '=='
  • он отделяет тест утверждения от логики ветвления, а не чередует их - это упрощает чтение и рефакторинг.

Ответ 7

Я иногда делаю:

if gender == 'm':
    greeting = 'Mr.'
else:
    assert gender == 'f'
    greeting = 'Ms.'

Я думаю, что это хорошо говорит читателю кода, что есть только (в данном случае) две возможности и то, что они есть. Хотя вы можете сделать пример для создания более описательной ошибки, чем AssertionError.