Python - условно перехватывающие исключения - PullRequest
15 голосов
/ 16 ноября 2011

Можно ли условно отлавливать исключения в python?Я хотел бы иметь возможность написать функцию, чтобы вызывающий мог решить, кто обрабатывает исключение.

В принципе, я хотел бы что-то вроде этого:

def my_func(my_arg, handle_exceptions):
    try:
        do_something(my_arg)
    except Exception, e if handle_exceptions:
        print "my_func is handling the exception"

Я знаю, что мог бы написать какой-нибудь клёвый код, который делает то, что я хочу, но я хочу получить питонный ответ, если он есть.
Спасибо.

Ответы [ 8 ]

22 голосов
/ 16 ноября 2011

Вы можете повторно вызвать исключение, если не хотите его обрабатывать:

def my_func(my_arg, handle_exceptions):
    try:
        do_something(my_arg)
    except Exception, e:
        if not handle_exceptions:
            # preserve prior stack trace
            raise

            # Or, if you dont care about the stack prior to this point
            #raise Exception(e)

            # similarly, you can just re-raise e.  The stack trace will start here though.
            #raise e
        else:
            print "my_func is handling the exception"

Другой вариант - создать свои собственные исключения, которые подкласс Exception (или конкретное исключение, например urllib2.HTTPError), а затем только поймать / выбросить (raise) ваше пользовательское исключение:

class MyException(Exception):
    def __init__(self, message):
        self.message = message

class MyExceptionTwo(Exception):
    def __init__(self, message):
        self.message = message
    def __repr__(self):
        return "Hi, I'm MyExceptionTwo.  My error message is: %s" % self.message

def something():
    if not tuesday:
        raise MyException("Error: it's not Tuesday.")
    else:
        raise MyExceptionTwo("Error: it's Tuesday.")

def my_func(my_arg):
    try:
        something()
    except MyException, e:
        print e.message
    # Will pass MyExceptionTwo up the call chain

def my_other_func():
    try:
        my_func(your_arg)
    except MyExceptionTwo, e:
        print str(e)
    # No need to catch MyException here since we know my_func() handles it
    # but we can hadle MyExceptionTwo here
14 голосов
/ 16 ноября 2011

На вопрос просто не хватает ответов; -)

Вот еще одна книга рекордов. Просто создайте фиктивное исключение:

class NeverMatch(Exception):
    'An exception class that is never raised by any code anywhere'

Затем используйте условное выражение, чтобы решить, соответствовать ли действительное исключение или исключение-заполнитель (которое никогда не вызывается):

try:
    do_something(my_arg)
except (Exception if handle_exceptions else NeverMatch) as e:
    print 'I am handling it'
5 голосов
/ 16 ноября 2011

Тип исключения может быть переменной.

def my_func(my_arg, handle_exceptions):
  if handle_exceptions:
    exc_type = Exception
  else:
    exc_type = None

  try:
    do_something(my_arg);
  except exc_type, e:
    print "my_func is handling the exception";

Запутанный Python ("Pythonic"?) Версия:

def my_func(my_arg, handle_exceptions):
  try:
    do_something(my_arg);
  except (handle_exceptions and Exception), e:
    print "my_func is handling the exception";

На самом деле работает без скобок, но пока мы запутываемся, давайте не будем путать людей с малоизвестными правилами, такими как приоритет, кроме операторов.

5 голосов
/ 16 ноября 2011

Вы можете использовать:

def my_func(my_arg, handle_exceptions):
  try:
    do_something(my_arg);
  except Exception as e:
    if not handle_exceptions: raise
    print "my_func is handling the exception";
4 голосов
/ 16 ноября 2011

Вы всегда можете поймать его и условно поднять его так:

def my_func(my_arg, handle_exceptions):
  try:
    do_something(my_arg)
  except Exception:
    if handle_exceptions:
      print "my_func is handling the exception"
      #handle it
    else: 
      print "my_func is NOT handling the exception"
      raise
2 голосов
/ 16 ноября 2011

У вас есть два основных варианта:

  1. Считайте handle_exceptions логическим значением и повторно поднимите, если False
  2. Считайте handle_exceptions исключениями для обработки

По логическому маршруту у вас есть два основных варианта:

def my_func(my_arg, handle_exceptions):
    try:
        do_something(my_arg)
    except Exception, e:
        if not handle_exceptions:
            raise
        print "my_func is handling the exception"

или

def my_func(my_arg, handle_exceptions):
    if handle_exceptions:
        exceptions = ValueError, IndexError # or whatever
    else:
        exceptions = NoExceptions # None in 2.x, or custom Exception class in 3.x
    try:
        do_something(my_arg)
    except exceptions, e:
        print "my_func is handling the exception"

Вдоль маршрута 'трактовать handle_exceptions как исключения для обработки' вы можете сделать это:

class NoExceptions(Exception):
    'Dummy exception, never raised'

def my_func(my_arg, handle_exceptions=NoExceptions):
    try:
        do_something(my_arg)
    except handle_exceptions, e:
        print "my_func is handling the exception"

и вы бы назвали это так:

my_func(some_arg, ValueError)  # to handle ValueErrors

или

my_func(some_arg)  # to not handle any exeptions

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

def my_func(my_arg, handle_exceptions=NoExceptions, handler=None):
    try:
        do_something(my_arg)
    except handle_exceptions, e:
        if handler is not None:
            handler(e)
        else:
            log_this_exception()
2 голосов
/ 16 ноября 2011

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

def my_func(my_arg, handle_exceptions):
  try:
    do_something(my_arg);
  except Exception, e:
    if handle_exceptions:
        print "my_func is handling the exception"
    else:
        raise
1 голос
/ 24 апреля 2012

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

from contextlib import contextmanager 

@contextmanager
def ignore_errors_if(exception_type, skip_condition): 
    try: 
        yield 
    except exception_type, excn: 
        if skip_condition: 
            logging.debug("SKIPPING EXCEPTION %s" % excn)  # etc... 
            pass 
        else: 
            raise excn 

Затем в своем коде вы можетеговорят:

def some_function(): 
    # ... 
    with ignore_errors_if(Exception, should_ignore_errors): 
        result = some_funciton_that_might_raise() 
    # Deal with result, although know that it might not be set... 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...