Как изящно включить 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