Поймать необратимые исключения и ре-рейз - PullRequest
3 голосов
/ 18 января 2012

Это продолжение моего вопроса Зависание в скрипте Python с использованием SQLAlchemy и многопроцессорной обработки .Как обсуждалось в этом вопросе, выборка исключений проблематична в Python.Обычно это не проблема, а один из случаев, когда это происходит, когда в модуле многопроцессорной обработки python возникают ошибки.Так как многопроцессорная обработка перемещает объекты путем травления, если в многопроцессорном процессе возникает ошибка, весь процесс может зависнуть, как показано в этом вопросе.

Один из возможных подходов - исправить все проблемные исключения, как обсуждалось ввопрос.Это нелегко, поскольку невозможно заранее узнать, какие исключения могут быть вызваны.Альтернативный подход, который был предложен lbolla в ответе на вопрос , состоит в том, чтобы перехватить исключение, создать эквивалентное безвредное исключение и затем отбросить.Тем не менее, я не уверен, как именно это сделать.Рассмотрим следующий код.

class BadExc(Exception):
    def __init__(self, message, a):
        '''Non-optional param in the constructor.'''
        Exception.__init__(self, message)
        self.a = a

import sys
try:
    try:
        #print foo
        raise BadExc("bad exception error message", "a")
    except Exception, e:
        raise Exception(e.__class__.__name__ + ": " +str(e)), None, sys.exc_info()[2]
except Exception, f:
    pass

import cPickle
a = cPickle.dumps(f)
l = cPickle.loads(a)
print "raising error"
raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]

Этот код выбирает и снимает исключение, а затем выбрасывает его, выдавая ошибку

raising error
Traceback (most recent call last):
  File "<stdin>", line 11, in <module>
Exception: BadExc: bad exception error message

Кредиты Ответ Гленна Мейнарда на ""Внутреннее исключение »(с отслеживанием) в Python?" .Это имеет важные вещи, а именно трассировку, сообщение об ошибке и тип исключения, так что это может быть лучшим из возможных.Но в идеале я хотел бы, чтобы что-то выглядело точно так же, как исходное исключение, а именно

Traceback (most recent call last):
  File "<stdin>", line 11, in <module>
__main__.BadExc: bad exception error message

или, в более общем смысле, с именем исключения впереди, а не Exception.Возможно ли это?

В качестве альтернативы вместо класса BadExc можно использовать оператор print foo, который дает NameError.Однако это исключение не требует специальной обработки.

1 Ответ

2 голосов
/ 19 января 2012

Вы можете переопределить sys.excepthook, чтобы достичь того, что вы хотите. По крайней мере, он работает для этого примера, но довольно хакерский, поэтому, пожалуйста, протестируйте, и никаких обещаний: -)

import sys

def excepthook_wrapper(type, value, traceback):
    if len(value.args) == 2:
        name, msg = value.args
        value.args = (msg,)
        sys.__excepthook__(name, value, traceback)
    else:
        sys.__excepthook__(type, value, traceback)

sys.excepthook = excepthook_wrapper

( Редактировать: Я не на самом деле доволен этим, потому что теперь «нормальные» исключения с двумя аргументами также будут обрабатываться по-другому. передавая "PICKLED" в качестве первого аргумента и затем проверяя это, вместо проверки длины args.)

А затем создайте Exception с двумя аргументами, именем (__module__.__class__) и сообщением Exception (str(e)):

try:
    try:
        #print foo
        raise BadExc("bad exception error message", "a")
    except Exception, e:
        cls = e.__class__
        if hasattr(cls, '__module__'):
            name = '{0}.{1}'.format(cls.__module__, cls.__name__)
        else:
            name = cls.__name__
        raise Exception(name, str(e)), None, sys.exc_info()[2]
except Exception, f:
    pass

Тогда это:

import cPickle
a = cPickle.dumps(f)
l = cPickle.loads(a)
print "raising error"
raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]

Печать:

raising error
Traceback (most recent call last):
  File "test.py", line 18, in <module>
    raise BadExc("bad exception error message", "a")
__main__.BadExc: bad exception error message
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...