【问题标题】:Valid syntax in both Python 2.x and 3.x for raising exception?Python 2.x 和 3.x 中用于引发异常的有效语法?
【发布时间】:2015-12-25 12:59:55
【问题描述】:

如何将此代码移植到 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")

【问题讨论】:

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


    【解决方案1】:

    您将不得不求助于使用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 版本。

    【讨论】:

    • 这看起来是一个绝妙的答案。我自己做了一些研究,然后找到了这样的解决方案:raise ConnectionError(BarException(e)).with_traceback(sys.exc_info()[2])(取自这里:diveintopython3.net/…)这是不好的风格吗?
    • @speendo:Python 2 异常没有 with_traceback() 方法,因此您不能在多语言代码中使用它。
    • 您所指的页面仅显示了使用2to3 工具将Python 2 移植到Python 3 代码时发生的情况,它没有告诉您如何编写在两个版本中都有效的代码。
    【解决方案2】:

    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 版本,以下代码将出现异常(字面意思)。

    # 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 的功能。它还带有 futurize 和 巴氏杀菌,定制的基于 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:
        ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-30
      • 1970-01-01
      • 2019-05-03
      • 1970-01-01
      • 2023-03-16
      • 2012-07-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多