将 Python3支持到 Python2

我有一个 Python 代码库,是为 Python 3构建的,它使用带编码参数的 Python 3样式 open () :

Https://github.com/miohtama/vvv/blob/master/vvv/textlineplugin.py#l47

    with open(fname, "rt", encoding="utf-8") as f:

现在我想将这段代码反向移植到 Python 2.x,这样我就有了一个可以与 Python 2和 Python 3一起工作的代码库。

解决 open()差异和缺少编码参数的建议策略是什么?

我可以有一个 Python3open()样式的文件处理程序,它流字节串,所以它将像 Python2open()的行为?

331149 次浏览

我觉得

from io import open

应该可以。

1. 在 Python 2中获取编码参数:

如果您只需要支持 Python 2.6和2.7,那么可以使用 io.open而不是 openio是 Python 3的新 io 子系统,它也存在于 Python 2、6 ans 2.7中。请注意,在 Python 2.6(以及3.0)中,它完全是在 Python 中实现的,速度非常慢,所以如果需要加快读取文件的速度,这不是一个好的选择。

如果需要速度,并且需要支持 Python 2.6或更早版本,则可以使用 codecs.open。它还有一个编码参数,与 io.open非常相似,只是它处理行结尾的方式不同。

2. 要获得一个 Python 3 open()样式的文件处理程序,它流字节串:

open(filename, 'rb')

注意“ b”,意思是“二进制”。

这可能会奏效:

import sys
if sys.version_info[0] > 2:
# py3k
pass
else:
# py2
import codecs
import warnings
def open(file, mode='r', buffering=-1, encoding=None,
errors=None, newline=None, closefd=True, opener=None):
if newline is not None:
warnings.warn('newline is not supported in py2')
if not closefd:
warnings.warn('closefd is not supported in py2')
if opener is not None:
warnings.warn('opener is not supported in py2')
return codecs.open(filename=file, mode=mode, encoding=encoding,
errors=errors, buffering=buffering)

然后您可以使用 python3方式保存代码。

请注意,有些 API (如 newlineclosefdopener)不能工作

这里有一个办法:

with open("filename.txt", "rb") as f:
contents = f.read().decode("UTF-8")

下面是如何在写作时做同样的事情:

with open("filename.txt", "wb") as f:
f.write(contents.encode("UTF-8"))

如果您正在使用 six,您可以尝试这样做,通过它可以利用最新的 Python 3 API,并且可以在 Python 2/3中运行:

import six


if six.PY2:
# FileNotFoundError is only available since Python 3.3
FileNotFoundError = IOError
from io import open


fname = 'index.rst'
try:
with open(fname, "rt", encoding="utf-8") as f:
pass
# do_something_with_f ...
except FileNotFoundError:
print('Oops.')

而且,放弃 Python 2支持只是删除与 six相关的所有内容。

这不是一个通用的答案,但是对于您喜欢使用缺省 python 2编码,但是希望为 python 3指定 utf-8的特定情况可能很有用:

if sys.version_info.major > 2:
do_open = lambda filename: open(filename, encoding='utf-8')
else:
do_open = lambda filename: open(filename)


with do_open(filename) as file:
pass