Python - условно улавливающие исключения
Можно ли условно перехватывать исключения в 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"
Я знаю, что могу написать какой-то kludgy-код, который делает то, что я хочу, но я хочу, чтобы питонский ответ был там, где он есть.
Спасибо.
Ответы
Ответ 1
Вы можете повторно создать исключение, если вы не хотите его обрабатывать:
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
), а затем только catch/throw (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 not Tuesday.")
else:
raise MyExceptionTwo("Error: it 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
Ответ 2
У вопроса просто недостаточно ответов; -)
Вот еще один для записей. Просто создайте фиктивное исключение:
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'
Ответ 3
Вы можете использовать:
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
Тип исключения может быть переменной.
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";
Obfuscated 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
Вы всегда можете его поймать и условно переподнять так:
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
Ответ 6
Да. Я предпочитаю положительные условия, когда это имеет смысл:
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
Ответ 7
У вас есть два основных варианта:
- Относитесь к
handle_exceptions
как к булевому, и re-raise if False
- Лечить
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"
По пути 'treat 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()
Ответ 8
Приятно выглядящая техника для улучшения других ответов заключается в том, чтобы обернуть логику условной обработки исключений в менеджер контекста, который можно повторно использовать, например:
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...