Python 2.x和3.x中的有效语法用于引发异常?

时间:2015-12-25 12:59:55

标签: python python-3.x exception python-2.x

如何将此代码移植到Python 3中,以便它可以在Python 2和Python 3中运行?

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 个答案:

答案 0 :(得分:5)

您必须使用exec(),因为您无法在Python 3中使用3参数语法;它会引发语法错误。

一如既往six library已覆盖您,移植到不依赖其他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版本。

答案 1 :(得分:5)

用于引发异常的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。

您可以使用2to3制作代码的Python 3副本。

  

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不同。我喜欢计划所有意外情况,因此如果使用2.7之前的Python版本,以下代码会出现异常(litteraly)。

# 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之间缺少的兼容层   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

请参阅http://python-future.org/上的python未来模块文档。 以下是该页面的“提升异常和暗示例外”部分的副本。

Raising Exceptions

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

Catching exceptions

仅限Python 2:

try:
    ...
except ValueError, e:
    ...

Python 2和3:

try:
    ...
except ValueError as e:
    ...