Valid syntax in both Python 2.x and 3.x for raising exception?
如何将此代码移植到 Python 3 以便它可以在 Python 2 和 Python3 中运行?
1 | raise BarException, BarException(e), sys.exc_info()[2] |
(复制自 http://blog.ionelmc.ro/2014/08/03/the-most-underrated-feature-in-python-3/)
奖金问题
做类似
的事情有意义吗
1 2 3 4 5 6 7 | 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 2 / 3 兼容代码
Six provides simple utilities for wrapping over differences between
Python 2 and Python 3. It is intended to support codebases that work
on both Python 2 and 3 without modification. six consists of only one
Python file, so it is painless to copy into a project.
http://pythonhosted.org/six/
1 2 3 4 | 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 is a Python program that reads Python 2.x source code and applies
a series of fixers to transform it into valid Python 3.x code. The
standard library contains a rich set of fixers that will handle almost
all code. 2to3 supporting library lib2to3 is, however, a flexible and
generic library, so it is possible to write your own fixers for 2to3.
lib2to3 could also be adapted to custom applications in which Python
code needs to be edited automatically....
2to3 can also write the needed modifications right back to the source
file. (Of course, a backup of the original is also be made unless -n
is also given.) Writing the changes back is enabled with the -w flag:
1 $ 2to3 -w example.py(from https://docs.python.org/3.0/library/2to3.html)
Python版本确定
如果要确定python版本,我推荐:
1 2 3 4 5 6 | 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 版本,以下代码将出现异常(字面意思)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # 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 is the missing compatibility layer between Python 2 and
Python 3. It allows you to use a single, clean Python 3.x-compatible
codebase to support both Python 2 and Python 3 with minimal overhead.It provides future and past packages with backports and forward ports
of features from Python 3 and 2. It also comes with futurize and
pasteurize, customized 2to3-based scripts that helps you to convert
either Py2 or Py3 code easily to support both Python 2 and 3 in a
single clean Py3-style codebase, module by module.
http://python-future.org/overview.html
请参阅 http://python-future.org/ 上的 python\\'s future 模块文档。
以下是该页面的"提高异常"和"排除异常"部分的副本。
引发异常
1 2 3 4 | import future # pip install future import builtins # pip install future import past # pip install future import six # pip install six |
仅限 Python 2:
1 | raise ValueError,"dodgy value" |
Python 2 和 3:
1 2 | raise ValueError("dodgy value") Raising exceptions with a traceback: |
仅限 Python 2:
1 2 | traceback = sys.exc_info()[2] raise ValueError,"dodgy value", traceback |
仅限 Python 3:
1 | raise ValueError("dodgy value").with_traceback() |
Python 2 和 3:选项 1
1 2 3 4 5 6 | 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
1 2 3 4 | from future.utils import raise_with_traceback raise_with_traceback(ValueError("dodgy value")) Exception chaining (PEP 3134): |
设置:
1 2 | class DatabaseError(Exception): pass |
仅限 Python 3
1 2 3 4 5 6 | 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:
1 2 3 4 5 6 7 8 | 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) |
测试上述内容:
1 2 3 4 | 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:
1 2 3 4 | try: ... except ValueError, e: ... |
Python 2 和 3:
1 2 3 4 | try: ... except ValueError as e: ... |
你将不得不使用
一如既往,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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):\ raise tp, value, tb\ ") |
现在你可以使用:
1 | reraise(BarException, BarException(e), sys.exc_info()[2]) |
无需进一步测试 Python 版本。