Каковы некоторые элегантные способы абстрагироваться от повторяющейся обработки исключений в Python? - PullRequest
11 голосов
/ 21 марта 2011

При обработке исключений в python я часто повторяю код.Базовый шаблон имеет вид:

try:
  action_here()
except CommonException1:
  Action_always_taken_for_CommonException1()
except CommonException2:
  Action_always_taken_for_CommonException2()
except Exception:
  Default_action_always_taken()

Что я хотел бы сделать, так это кое-кому как абстрагировать этот повторяющийся код от функции или класса.Я знаю один способ сделать это, чтобы вызвать функцию обработки исключений с объектом исключения, например:

try:
  action_here()
except Exception as e:
  handle_exception(e)

Затем в этой функции определите исключение на основе класса.

def handle_exception(e):
  if type(e) == type(CommonException1()):
    Action_always_taken_for_CommonException1()
  elif type(e) == type(CommonException2()):
    Action_always_taken_for_CommonException2())
  else:
    Default_action_always_taken()

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

Ответы [ 3 ]

19 голосов
/ 21 марта 2011

Эта ситуация является одним из основных вариантов использования для менеджеров контекста и оператора with:

from __future__ import with_statement # Needed in 2.5, but not in 2.6 or later

from contextlib import contextmanager

@contextmanager
def handle_exceptions():
    try:
        yield # Body of the with statement effectively runs here
    except CommonException1:
        Action_always_taken_for_CommonException1()
    except CommonException2:
        Action_always_taken_for_CommonException2()
    except Exception:
        Default_action_always_taken()

# Used as follows
with handle_exceptions():
    action_here()
6 голосов
/ 21 марта 2011

Если вам не нравятся повторяющиеся блоки if / elseif, вы можете поместить свои ручки в диктовку, набираемую по типу:

handlers = { type(CommonException1()) : Action_always_taken_forCommonException1,
             type(CommonException2()) : Action_always_taken_forCommonException2 }

def handle_exception(te):
  if te in handlers:
    handlers[te]()
  else:
    Default_action()

, которую затем можно запустить:

try:
  action_here()
except Exception as e:
  handle_exception(type(e))

Кроме того: Если вы часто пишете эти блоки try, вы можете написать свой собственный менеджер контекста (см. здесь ).На стороне action_here() ваш код будет выглядеть следующим образом:

with my_error_handling_context():
  action_here1()
  action_here2()

В этом случае код handle_exception по существу будет методом __exit__ вашего диспетчера контекста (который всегда будет передаваться любомуисключения подняты во время с блоком).

5 голосов
/ 21 марта 2011

Хотя решение, использующее диспетчер контекста (предложенное другими), является наиболее элегантным и было бы тем, что я бы порекомендовал, я хотел бы отметить, что ваша функция handle_exception может быть написана более элегантно-поднятие исключения:

def handle_exception(e):
  try:
    raise e
  except CommonException1:
    Action_always_taken_for_CommonException1()
  except CommonException2:
    Action_always_taken_for_CommonException2()
  except Exception:
    Default_action_always_taken()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...