Действительный синтаксис в 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

(из https://docs.python.org/3.0/library/2to3.html)

Определение версии 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:
    ...
Другие вопросы по тегам