Python вложенная попытка, кроме vs if, elif, else

Я пытаюсь ознакомиться с лучшими практиками Python. Согласно Zen of Python, проще попросить прощения, чем попросить разрешения, однако в нем также говорится, что квартира лучше, чем количество вложенных и читаемых. Как бы вы справились с этим:

У меня есть 3 словаря. У меня есть ключ, и я хочу проверить, находится ли ключ в словаре. Ключ будет только в одном из них. В зависимости от того, в каком словаре он находится, я хочу делать разные вещи.

Используя try/except, я прихожу к следующему решению:

try:
    val = dict1[key]
except KeyError:
    try:
        val = dict2[key]
    except KeyError:
        try:
            val = dict3[key]
        except KeyError:
            do_stuff_key_not_found()
        else:
            do_stuff_dict3()
    else:
        do_stuff_dict2()
else:
    do_stuff_dict1()

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

Более простым решением было бы:

if key in dict1:
    val = dict1[key]
    do_stuff_dict1()
elif key in dict2:
    val = dict2[key]
    do_stuff_dict2()
elif key in dict3:
    val = dict3[key]
    do_stuff_dict3()
else:
    do_stuff_key_not_found()

Чем больше у Pythonic способ справиться с подобным случаем? Должен ли я придерживаться принципа EAFP или быть более плоским и читабельнее?

0
источник поделиться
2 ответа

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

Обе версии включают повторение кода и, таким образом, могут стать громоздкими, если вы имеете дело с большим количеством случаев. Один из способов борьбы с этим - вытащить пары dict/function в список, а затем перебрать по списку:

handlers = [ (dict1, do_stuff_dict1), (dict2, do_stuff_dict2), (dict3, do_stuff_dict3) ]
for whichDict, whichFunc in handlers:
    try:
        val = whichDict[key]
    except KeyError:
        continue
    else:
        whichFunc()
        break
else:
    do_stuff_not_found()
+6
источник

Я предпочитаю использовать dict.get(key, default_value), чтобы избежать обработки исключений, например:

handlers = [(d1, func_1), (d2, func_2)]
handlers_found = [(d, func) for d, func in handlers if d.get(key)]
if handlers_found:
    handlers_found[0][1]()
else:
    do_stuff_not_found()

get (key [, default]) Возвращает значение для ключа, если ключ находится в словаре, иначе по умолчанию. Если значение по умолчанию не задано, по умолчанию оно равно None, так что этот метод никогда не вызывает KeyError. https://docs.python.org/2/library/stdtypes.html

+1
источник

Посмотрите другие вопросы по меткам или Задайте вопрос