Подтвердить что ты не робот

Элегантная альтернатива длинным цепям исключений?

Много раз я нахожу, что пишу что-то вроде этого:

try:
    procedure_a()
except WrongProcedureError:
    try:
        procedure_b()
    except WrongProcedureError:
        try:
            procedure_c()
        except WrongProcedureError:
            give_up()

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

4b9b3361

Ответ 1

Для этого можно использовать конструкцию for/else:

for proc in [procedure_a, procedure_b, procedure_c]:
    try:
        proc()
    except WrongProcedureError:
        continue
    else:
        break
else:
    give_up()

Предложение else цикла for срабатывает только тогда, когда элемент управления падает с нижней части предложения for. Если break из (как вы, если какой - либо из трех процедур не сгенерирует исключение), это не сработает.

Ответ 2

Проходите через процедуры. Оберните петлю в функцию. Возврат из функции преждевременно в случае успеха:

def try_all():
    for procedure in [procedure_a, procedure_b, procedure_c]:
        try:
            procedure()
            return
        except WrongProcedureError:
            continue
    give_up()

Ответ 3

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

Другие подходы также работают, но они несколько сложнее понять и, вероятно, предпочтительнее, если у вас есть много (не только 3) функции, которые вы хотите проверить. В этом случае я бы действительно сделал функцию, чтобы скрыть эту сложность.

import itertools
from contextlib import suppress

def call_functions(funcs, give_up_func):
    for func in itertools.chain(funcs, [give_up_func]):
        with suppress(WrongProcedureError):
            func()
            return  # only reached when func does not raise WrongProcedureError.

Это предполагает, что give_up_func не будет поднимать то, что Exception и suppress требует python 3 (я думаю, 3.4).

Однако в вашем коде может быть что-то принципиально неправильное, когда вам это действительно нужно. Это похоже на какую-то "резервную" операцию, которая, вероятно, должна быть решена с использованием подклассов или дополнительного аргумента или стратегии/фабрики вместо вложенных try и except s.