2016-09-21 2 views
2

Что такое хороший способ, чтобы добавить дополнительную информацию в исключение PythonИсключения Design Pattern для более описательных исключений

Например я вложенные словари, как так

d = {'Bob':{'lastname':'Smith'}, 'Sally':{}} 

если доступ к словарю, как это Я получаю то, что я хочу, что фамилия

name = 'Bob' 
value = 'lastname' 
print(d[name][value]) 

Smith

Если я пытаюсь доступа фамилию Салли я также получить то, что я хочу что является KeyError

name = 'Sally' 
value = 'lastname' 
print(d[name][value]) 

KeyError: 'lastname'

Однако моя проблема в том, что это исключение крайне undescriptive мой код выглядит как этот

try: 
    name = 'Sally' 
    value = 'lastname' 
    print(d[name][value]) 
except KeyError: 
    raise KeyError("{0} has no {1}".format(name, value)) 

KeyError: Sally has no lastname

Это дает мне описательную ошибку, которую я ищу, но мне осталось интересно, является ли эта реализация питоновой. Есть ли лучший способ выразить это? Я пробовал просматривать документацию на python и другие распространенные пакеты, но не нашел ничего убедительного в том, что, по крайней мере, я мог видеть

+1

Использование '' Billy'' в вашем втором элементе поднимет 'KeyError: 'Billy не имеет последнего имени'', хотя' 'Billy'' не существует. – metatoaster

+0

Это хороший момент. Я этого не думал. Очень признателен, что вы указали на это – canyon289

ответ

1

Давайте просто разместим его там и посмотрим, к чему это приведет. Но сначала, посмотрите на article Джеффу Кнупп на эту тему. Это может быть обзор, но там есть большие маленькие самородки.

Рассмотрим LBYL (раз отмерь - в статье) подход:

if name not in d: 
    raise KeyError('{0} is not in first level of dict'.format(name)) 

if value not in d[name]: 
    raise KeyError('{0} is not in second level of {1}-dict'.format(value, name)) 

против ЭСПЦ (проще попросить прощения, чем разрешения - опять же, см статью) подход:

try: 
    lastnames = d[name] 
except KeyError: 
    raise KeyError('{0} is not in the first level of dict'.format(name)) 

try: 
    person = lastnames[value] 
except KeyError: 
    raise KeyError('{0} is not in the second level of {1}-dict'.format(value, name)) 

Теперь рассмотрим Zen of Python. На мой взгляд, прежний подход является более «красивым» и «более простым». Это также поражает меня как «удобочитаемое», хотя и с небольшим отрывом для этого случая. С другой стороны, последний более «явный» в том, что он четко указывает на возможность неудачи и как справиться с такими случаями. Кроме того, если вам когда-либо понадобится расширять деятельность вокруг обработки ошибок, нельзя «игнорировать» «практичность» подхода EAFP; если вам это нужно, мощность и удобство полного предложения try: except: else: finally не следует недооценивать. Сказав это, я лично склоняюсь к вашему решению try: except:.

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

Не против меня. В конце концов, это мнение.