Действительный синтаксис в Python 2.x и 3.x для возбуждения исключения?
Как я могу перенести этот код на Python 3, чтобы он работал как в Python 2, так и в Python3?
raise BarException, BarException(e), sys.exc_info()[2]
(скопировано с http://blog.ionelmc.ro/2014/08/03/the-most-underrated-feature-in-python-3/)
Бонусный вопрос
Есть ли смысл делать что-то вроде
IS_PYTHON2 = sys.version_info < (3, 0)
if IS_PYTHON2:
raise BarException, BarException(e), sys.exc_info()[2]
# replace with the code that would run in Python 2 and Python 3 respectively
else:
raise BarException("Bar is closed on Christmas")
2 ответа
Вам придется прибегнуть к использованию exec()
потому что вы не можете использовать синтаксис с тремя аргументами в Python 3; это вызовет синтаксическую ошибку.
Как всегда six
библиотека уже покрыта, портирована, чтобы не зависеть от других six
По определению их версия выглядит так:
import sys
if sys.version_info[0] == 3:
def reraise(tp, value, tb=None):
if value is None:
value = tp()
if value.__traceback__ is not tb:
raise value.with_traceback(tb)
raise value
else:
exec("def reraise(tp, value, tb=None):\n raise tp, value, tb\n")
Теперь вы можете использовать:
reraise(BarException, BarException(e), sys.exc_info()[2])
без дальнейшего тестирования для версии Python.
Python 2 / 3 совместимый код для вызова исключения
Six предоставляет простые утилиты для переноса различий между Python 2 и Python 3. Он предназначен для поддержки кодовых баз, которые работают на Python 2 и 3 без изменений. Шесть состоит только из одного файла Python, поэтому копировать в проект безболезненно. http://pythonhosted.org/six/
from six import reraise as raise_ # or from future.utils import raise_
traceback = sys.exc_info()[2]
err_msg = "Bar is closed on Christmas"
raise_(ValueError, err_msg, traceback)
Преобразование из Python 2 в Python 3.
Вы можете сделать копию кода на Python 3, используя 2to3.
2to3 - это программа на Python, которая читает исходный код Python 2.x и применяет ряд исправлений для преобразования его в действительный код Python 3.x. Стандартная библиотека содержит богатый набор исправлений, которые будут обрабатывать практически весь код. Библиотека поддержки 2to3 lib2to3, однако, является гибкой и универсальной библиотекой, поэтому можно написать собственные фиксаторы для 2to3. lib2to3 также может быть адаптирован для пользовательских приложений, в которых код Python должен редактироваться автоматически.
...
2to3 также может записать необходимые изменения прямо в исходный файл. (Конечно, резервная копия оригинала также может быть сделана, если не указан ключ -n.) Запись изменений включена с флагом -w:
$ 2to3 -w example.py
Определение версии Python
Если вы хотите определить версию Python, я рекомендую:
PY2 = sys.version_info.major == 2
PY3 = sys.version_info.major == 3
# or
import six # Python 2 / 3 compatability module
six.PY2 # is this Python 2
six.PY3 # is this Python 3
Python решения, основанные на версии
Не забывайте, что ранние версии Python 2 будут отличаться от 2.7. Мне нравится планировать все непредвиденные обстоятельства, поэтому следующий код принимает исключение (буквально), если используется версия Python до 2.7.
# If you want to use and if/then/else block...
import sys
major = sys.version_info.major
minor = sys.version_info.minor
if major == 3: # Python 3 exception handling
print("Do something with Python {}.{} code.".format(major, minor))
elif major == 2: # Python 2 exception handling
if minor >= 7: # Python 2.7
print("Do something with Python {}.{} code.".format(major, minor))
else: # Python 2.6 and earlier exception handling
assert minor >= 2, "Please use Python 2.7 or later, not {}.{}.".format(major,minor)
else:
assert major >= 2, "Sorry, I'm not writing code for pre-version 2 Python. It just ain't happening. You are using Python {}.{}.".format(major,minor)
assert major > 3, "I can't handle Python versions that haven't been written yet.. You are using Python {}.{}.".format(major,minor)
Обработка исключений в Python 2 и 3
python-future - это отсутствующий уровень совместимости между Python 2 и Python 3. Он позволяет использовать одну чистую кодовую базу, совместимую с Python 3.x, для поддержки как Python 2, так и Python 3 с минимальными издержками.
Он предоставляет будущие и прошлые пакеты с портами переноса и перенаправлениями функций из Python 3 и 2. Он также поставляется с настраиваемыми сценариями на основе 2to3, предназначенными для футурирования и пастеризации, которые помогают легко преобразовывать код Py2 или Py3 для поддержки как Python 2, так и 3. в одной чистой кодовой базе в стиле Py3, модуль за модулем. http://python-future.org/overview.html
Смотрите документацию по будущему модулю python по адресу http://python-future.org/. Ниже приведена копия разделов "Повышение исключений" и "Исключения катаклизма".
Возбуждение исключений
import future # pip install future
import builtins # pip install future
import past # pip install future
import six # pip install six
Только Python 2:
raise ValueError, "dodgy value"
Python 2 и 3:
raise ValueError("dodgy value")
Raising exceptions with a traceback:
Только Python 2:
traceback = sys.exc_info()[2]
raise ValueError, "dodgy value", traceback
Только Python 3:
raise ValueError("dodgy value").with_traceback()
Python 2 и 3: вариант 1
from six import reraise as raise_
# or
from future.utils import raise_
traceback = sys.exc_info()[2]
raise_(ValueError, "dodgy value", traceback)
Python 2 и 3: вариант 2
from future.utils import raise_with_traceback
raise_with_traceback(ValueError("dodgy value"))
Exception chaining (PEP 3134):
Настроить:
class DatabaseError(Exception):
pass
Только Python 3
class FileDatabase:
def __init__(self, filename):
try:
self.file = open(filename)
except IOError as exc:
raise DatabaseError('failed to open') from exc
Python 2 и 3:
from future.utils import raise_from
class FileDatabase:
def __init__(self, filename):
try:
self.file = open(filename)
except IOError as exc:
raise_from(DatabaseError('failed to open'), exc)
Тестирование выше:
try:
fd = FileDatabase('non_existent_file.txt')
except Exception as e:
assert isinstance(e.__cause__, IOError) # FileNotFoundError on Py3.3+ inherits from IOError
Ловля исключений
Только Python 2:
try:
...
except ValueError, e:
...
Python 2 и 3:
try:
...
except ValueError as e:
...