python продолжить, если условие не выполнено

Я часто ловлю себя на том, что хочу сделать что-то вроде этого, у меня есть что-то завернутое в try excepts, как это

item= get_item()
try:
    do_work(item)
except SomeError as err:
    if err.code == 123:
        do_something(item)
    else:
        # Actually I don't want to do something with this error code... I want to handle in 'except'
except:
    put_back(item)
    raise

есть ли способ подняться в except блок ниже другого? (a continue было бы неплохо) я в конечном итоге делает что-то вроде следующего, который не такой чистый!--5-->

item= get_item()
try:
    try:
        do_work(item)
    except SomeError as err:
        if err.code == 123:
            do_something(item)
        else:
            raise
 except:
     put_back(item)
     raise

есть ли вообще это сделать?

4 ответов


если вы используете достаточно недавнюю версию python (2.5 и выше), вы должны переключиться на использование контекст менеджер вместо:

class WorkItemContextManager(object):
    def __enter__(self):
        self.item = get_item()
        return self.item

    def __exit__(self, exc_type, exc_value, tb):
        if exc_type is not None:
            if exc_type is SomeError and exc_value.code == 123:
                do_something(self.item)
                return True  # Exception handled
            put_back(self.item)

затем:

with WorkItemContextManager() as item:
    do_work(item)

на __exit__ метод может вернуть True, если было обработано исключение; возврат None вместо этого повторно вызовет любые исключения, вызванные в with блок.

если нет, вы ищете finally блок вместо:

item = get_item()
try:
    do_work(item)
    item = None
except SomeError as err:
    if err.code == 123:
        do_something(item)
        item = None
finally:
    if item is not None:
        put_back(item)

на finally suite гарантированно быть выполнены, когда try: комната завершает, или произошло исключение. Установив item to None вы в основном говорите finally suite все завершено просто отлично,не нужно возвращать его.

на finally обработчик берет на себя от вашего одеяла except обработчик. Если было исключение в do_work, item не будет установлено значение None. Если SomeError обработчик не перехватывает исключение, или err.code is не 123, item будет также не устанавливайте значение None, и таким образом put_back(item) метод выполняется.


хорошо иметь в виду, что try-кроме flow, и одним из их преимуществ является то, что они устраняют необходимость переменных состояния и проверок состояния, таких как

if not foo:
    # do something

кроме того, класс исключения должен представлять определенный тип ошибки. Если вам нужно принять дальнейшие решения о типе ошибки в блоке except, это хороший признак того, что класс недостаточно специфичен для представления состояния программы. Лучше всего подкласс SomeError и только поймать подкласс в первом кроме. Тогда другие экземпляры SomeError попадут во второй блок, кроме блока.


моим предложением было бы создать функцию (или серию функций), которая обертывает ошибки метода, которые вы хотите контролировать. Что-то вроде того...

def wrapper(arg):
    try:      
        do_work(arg)
    except SomeError as e:
        if e.code == 123:
           do_something(item)
           # Other possible cleanup code
        else:
           raise

...потом, когда захочешь позвонить...

try:
    wrapper(arg)
except SomeError as e:
    put_back(arg)

контексте менеджеры отличные, но для некоторых простых случаев, когда вы не будете повторно использовать логику в другом месте, они могут быть немного тяжелым.

вместо того, чтобы пытаться иметь несколько except блоки, вы можете просто проверить исключение внутри одного except блок:

item= get_item()
try:
    do_work(item)
except Exception as err:
    if isinstance(err, SomeError) and err.code == 123:
        do_something(item)
    else:
        put_back(item)
        raise

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

будьте осторожны, что код, который действительно принадлежит в finally не заканчивается здесь.