Как изящно включить Python 3.3 из синтаксиса исключений None в программу Python 3.2?

Я пытаюсь повторно вызвать исключение, чтобы предоставить пользователю более подробную информацию о фактической ошибке. Python 3.3 включает в себя PEP 409. Добавляет raise NewException from None синтаксис для подавления контекста исходного исключения.

Тем не менее, я ориентируюсь на Python 3.2. Сценарий Python будет анализироваться, но во время выполнения, если он встречает from None Синтаксис это будет производить TypeError: exception causes must derive from BaseException, Например:

try:
    regex_c = re.compile('^{}$'.format(regex)) 
except re.error as e:
    e_msg = 'Regular expression error in "{}"'.format(regex)
    e_reraise = Exception(e_msg)
    # Makes use of the new Python 3.3 exception syntax [from None]
    # to suppress the context of the original exception
    # Causes an additional TypeError exception in Python 3.2
    raise e_reraise from None

Инкапсуляция raise e_reraise from None в try просто производит еще большее исключение стека трассировки. Проверка версии тоже не работает, так как мой python3.3 на Xubuntu 12.10 тянет модули из /usr/lib/python3/dist-packages/* который был настроен для модулей Python3.2. (Вы получаете удобный Error in sys.excepthook: который создает массивную трассировку.)

Есть ли способ использовать функцию PEP 409 при работе в Python 3.3, одновременно игнорируя ее в Python 3.2?

2 ответа

Решение

PEP, который вы связали, обеспечивает решение:

  • raise NewException() from None

Следует существующему синтаксису явного объявления исходного исключения

  • exc = NewException(); exc.__context__ = None; raise exc

Очень многословный способ предыдущего метода

Таким образом, вы просто должны избегать нового синтаксиса и использовать подробный эквивалент.

Если вы не хотите видеть назначения, вы можете поместить код в функцию:

def suppress_context(exc):
    exc.__context__ = None
    return exc

А затем сделайте:

raise suppress_context(TheErrorClass())

Редактировать: как указал Martijn PEP 415 изменил это поведение:

Подвести итоги, raise exc from cause будет эквивалентно:

exc.__cause__ = cause
raise exc

Таким образом, вместо установки __context__ в None вы должны установить __cause__ в None,

Если вы действительно хотите использовать новый синтаксис, то единственный способ сделать это - заменить sys.excepthook с чем-то, что анализирует вывод трассировки и удаляет части, которые вам не нужны. Но в этом случае вы также должны сделать это:

try:
    raise error from None
except TypeError:
    raise error

Тогда excepthook следует искать трассировку и, если она должна удалить части, связанные с raise error from None линия. Не простая задача, и вы получите больше кода, чем другое решение.

Вы можете установить exc.__cause__ = None подавить контекстную печать в Python 3.3:

except re.error as e:
    e_msg = 'Regular expression error in "{}"'.format(regex)
    e_reraise = Exception(e_msg)
    e_reraise.__cause__ = None  # 'raise e_reraise from None'
    raise e_reraise    

В Python 3.3, когда вы используете raise exc from cause что на самом деле происходит:

exc.__cause__ = cause
raise exc

и настройка exc.__cause__ в свою очередь неявно устанавливает exc.__suppress_context__ = True, См. PEP 415, в котором подробно описано, как raise exc from None обрабатывается.

Когда вы установите exc.__cause__ = None в Python 3.2 ничего не меняется:

$ python3.2
Python 3.2.3 (default, Apr 13 2012, 13:31:19) 
[GCC 4.2.1 Compatible Apple Clang 3.0 (tags/Apple/clang-211.12)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> try:
...     raise ValueError()
... except:
...     exc = TypeError()
...     exc.__cause__ = None
...     raise exc
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ValueError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 6, in <module>
TypeError

Но в Python 3.3 контекст подавляется:

$ python3.3
Python 3.3.0 (default, Sep 29 2012, 08:16:08) 
[GCC 4.2.1 Compatible Apple Clang 3.1 (tags/Apple/clang-318.0.58)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> try:
...     raise ValueError()
... except:
...     exc = TypeError()
...     exc.__cause__ = None
...     raise exc
... 
Traceback (most recent call last):
  File "<stdin>", line 6, in <module>
TypeError

как если бы вы использовали raise exc from None:

>>> try:
...     raise ValueError()
... except:
...     raise TypeError() from None
... 
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
TypeError
Другие вопросы по тегам