如何将这段代码移植到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")
Martijn Piet.. 9
您必须诉诸使用,exec()
因为您无法在Python 3中使用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版本。
您必须诉诸使用,exec()
因为您无法在Python 3中使用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和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版本,我建议:
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 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的功能的反向移植和正向移植。它还带有未来化和巴氏灭菌,基于2to3的定制脚本,可帮助您轻松转换Py2或Py3代码以同时支持Python 2和3。在单个干净的Py3样式的代码库中,逐模块进行。 http://python-future.org/overview.html
请参阅http://python-future.org/上的 python的未来模块文档。以下是该页面的“提高例外情况”和“例外情况”部分的副本。
import future # pip install future import builtins # pip install future import past # pip install future import six # pip install six
raise ValueError, "dodgy value"
raise ValueError("dodgy value") Raising exceptions with a traceback:
traceback = sys.exc_info()[2] raise ValueError, "dodgy value", traceback
raise ValueError("dodgy value").with_traceback()
from six import reraise as raise_ # or from future.utils import raise_ traceback = sys.exc_info()[2] raise_(ValueError, "dodgy value", traceback)
from future.utils import raise_with_traceback raise_with_traceback(ValueError("dodgy value")) Exception chaining (PEP 3134):
class DatabaseError(Exception): pass
class FileDatabase: def __init__(self, filename): try: self.file = open(filename) except IOError as exc: raise DatabaseError('failed to open') from exc
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
try: ... except ValueError, e: ...
try: ... except ValueError as e: ...