注:本文的作者是 Ed Schofield。原文的地址为: Cheat Sheet: Writing Python 2-3 compatible code
该笔记向你展示了编写不会过时的兼容 Python 2 和 Python 3 的代码风格。
它是 Ed Schofield 在 PyCon AU 2014 的演讲,“ Writing 2/3 compatible code ”。
最低版本:
- Python 2: 2.6+
- Python 3: 3.3+
安装
一些下面的 imports
适用于使用 pip
安装在 PyPI 上安装:
import future # pip install future
import past # pip install past
import six # pip install six
以下的脚本也适用于 pip
安装:
futurize # pip install futurize
pasteurize # pip install pasteurize
查看 http://python-future.org 和 https://pythonhosted.org/six/ 获取更多消息。
基本语法差异
print:
# Python 2 only:
print 'Hello'
# Python 2 and 3:
print('Hello')
为了打印出多个 strings。 import print_function
来防止 Py2 把它解释成一个元组。
# Python 2 only:
print 'Hello', 'Guido'
# Python 2 and 3:
from __future__ import print_function # (at top of module)
print('Hello', 'Guido')
# Python 2 only:
print >> sys.stderr, 'Hello'
# Python 2 and 3:
from __future__ import print_function
print('Hello', file=sys.stderr)
# Python 2 only:
print 'Hello',
# Python 2 and 3:
from __future__ import print_function
print('Hello', end='')
抛出异常
# Python 2 only:
raise ValueError, "dodgy value"
# Python 2 and 3:
raise ValueError("dodgy value")
使用 traceback 抛出异常:
# Python 2 only:
traceback = sys.exc_info()[2]
raise ValueError, "dodgy value", traceback
# Python 3 only:
raise ValueError("dodgy value").with_traceback()
# Python 2 and 3: option 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 and 3: option 2
from future.utils import raise_with_traceback
raise_with_traceback(ValueError("dodgy value"))
异常链 (PEP 3134):
# Setup:
class DatabaseError(Exception):
pass
# Python 3 only
class FileDatabase:
def __init__(self, filename):
try:
self.file = open(filename)
except IOError as exc:
raise DatabaseError('failed to open') from exc
# Python 2 and 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)
# Testing the above:
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 only:
try:
...
except ValueError, e:
...
# Python 2 and 3:
try:
...
except ValueError as e:
...
除法
整除(rounding down):
# Python 2 only:
assert 2 / 3 == 0
# Python 2 and 3:
assert 2 // 3 == 0
“True division” (float division):
# Python 3 only:
assert 3 / 2 == 1.5
# Python 2 and 3:
from __future__ import division # (at top of module)
assert 3 / 2 == 1.5
“Old division” (i.e. compatible with Py2 behaviour):
# Python 2 only:
a = b / c # with any types
# Python 2 and 3:
from past.utils import old_div
a = old_div(b, c) # always same as / on Py2
长整数
短整数在 Python 3 中已经去除了,并且 long
已经变成了 int
(没有 L
在 repr
后面)
# Python 2 only
k = 9223372036854775808L
# Python 2 and 3:
k = 9223372036854775808
# Python 2 only
bigint = 1L
# Python 2 and 3
from future.builtins import int
bigint = int(1)
为了测试一个值是否是整数(任何类型):
# Python 2 only:
if isinstance(x, (int, long)):
...
# Python 3 only:
if isinstance(x, int):
...
# Python 2 and 3: option 1
from future.builtins import int # subclass of long on Py2
if isinstance(x, int): # matches both int and long on Py2
...
# Python 2 and 3: option 2
from past.builtins import