如何编写与Python 2和Python 3兼容的异常重新加载代码?

Hon*_*gli 24 python python-2.x python-3.x

我正在尝试使我的WSGI服务器实现与Python 2和Python 3兼容.我有这样的代码:

def start_response(status, response_headers, exc_info = None):
    if exc_info:
        try:
            if headers_sent:
                # Re-raise original exception if headers sent.
                raise exc_info[0], exc_info[1], exc_info[2]
        finally:
            # Avoid dangling circular ref.
            exc_info = None
    elif headers_set:
        raise AssertionError("Headers already set!")

    headers_set[:] = [status, response_headers]
    return write
Run Code Online (Sandbox Code Playgroud)

......相关部分是:

# Re-raise original exception if headers sent.
raise exc_info[0], exc_info[1], exc_info[2]
Run Code Online (Sandbox Code Playgroud)

Python 3不再支持该语法,因此必须将其翻译为:

raise exc_info[0].with_traceback(exc_info[1], exc_info[2])
Run Code Online (Sandbox Code Playgroud)

问题:Python 2语法在Python 3中生成解析错误.如何编写可由Python 2和Python 3解析的代码?我尝试了以下,但这不起作用:

if sys.version_info[0] >= 3:
    raise exc_info[0].with_traceback(exc_info[1], exc_info[2])
else:
    eval("raise exc_info[0], exc_info[1], exc_info[2]; 1", None, { 'exc_info': exc_info })
Run Code Online (Sandbox Code Playgroud)

Jon*_*ric 48

你能用six吗?它的存在是为了解决这个问题.

import six, sys
six.reraise(*sys.exc_info())
Run Code Online (Sandbox Code Playgroud)

请参阅:https://pythonhosted.org/six/index.html#six.reraise


Inb*_*ose 0

你可以做一些有创意的事情。

在代码的开头进行检查 - 您的构造函数或其他内容,检查您正在使用的 python 版本,因为您的正常版本检查器不起作用,请尝试以下操作:

try:
  eval('a python 3 expression') # something that only works in python3+
  python_version = 3
except:
  python_version = 2
Run Code Online (Sandbox Code Playgroud)

然后代码的其余部分可以轻松地引用它来知道要使用什么。

至于解析错误,您可以在函数中使用 exec,如下所示:

def what_to_run():
    if python_version = 3:
        return 'raise exc_info[0].with_traceback(exc_info[1], exc_info[2])'
    else:
        return 'raise exc_info[0], exc_info[1], exc_info[2]'
Run Code Online (Sandbox Code Playgroud)

在你的函数中你可以这样写:

def start_response(status, response_headers, exc_info = None):
    if exc_info:
        try:
            if headers_sent:
                # Re-raise original exception if headers sent.
                exec(what_to_run())
        finally:
            # Avoid dangling circular ref.
            exc_info = None
    elif headers_set:
        raise AssertionError("Headers already set!")

    headers_set[:] = [status, response_headers]
    return write
Run Code Online (Sandbox Code Playgroud)

有点混乱,未经测试,但它应该可以工作,至少你理解这个想法。

  • 不要这样做。正如另一个答案所建议的那样,请使用“六”。 (7认同)
  • 检查Python 不是问题。问题是 Python 3 兼容的代码在 Python 2 上生成*解析错误*,反之亦然。我不能像通常那样将两个版本放在 if-else 或 try- except 块中。 (5认同)