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
не заканчивается здесь.