将 Python 3 open(encoding="utf-8") 向后移植到 Python 2

Posted

技术标签:

【中文标题】将 Python 3 open(encoding="utf-8") 向后移植到 Python 2【英文标题】:Backporting Python 3 open(encoding="utf-8") to Python 2 【发布时间】:2012-06-13 19:44:36 【问题描述】:

我有一个为 Python 3 构建的 Python 代码库,它使用 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() 差异和缺少编码参数的推荐策略是什么?

我能否有一个 Python 3 open() 样式的文件处理程序来流式传输字节字符串,所以它的行为类似于 Python 2 open()

【问题讨论】:

【参考方案1】:

这是一种方法:

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"))

【讨论】:

如果您对f 有不同的计划,这显然不起作用 没错,如果你想写入这个文件而不是读取呢? @Orb 我已经编辑了我的回答帖子来回答你的问题。 请注意,此答案帖子中的 contents 是 Python 3 中的字符串(它是 Python 2 中的 Unicode 字符串)。【参考方案2】:

不是一般的答案,但对于您对默认的 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

【讨论】:

【参考方案3】:

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

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

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

2。要获取流字节串的 Python 3 open() 样式文件处理程序:

open(filename, 'rb')

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

【讨论】:

“b”实际上表示二进制模式,而不是字节。见docs.python.org/3/library/functions.html#open。 @pmdarrow 在这种情况下也是如此,但严格来说,是的。 我遇到了一个问题,你不能在选项 2 的字节流上运行正则表达式 ;) @macmadness86 您需要使用字节正则表达式。 移植指南中的一条注释:“不要为使用 codecs.open() 的过时做法而烦恼,因为这只是为了保持与 Python 2.5 的兼容性所必需的。” docs.python.org/3/howto/pyporting.html【参考方案4】:

如果你使用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 相关的所有内容。

【讨论】:

【参考方案5】:

这可能会奏效:

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 的方式。

请注意,newlineclosefdopener 等某些 API 不起作用

【讨论】:

您可以反转条件以避免pass【参考方案6】:

我觉得

from io import open

应该这样做。

【讨论】:

我认为 Lennart 下面的回答要好得多,因为它提供了更多解释和关于 io 模块在 2.x 中运行缓慢的警告以及使用 codecs.open 的建议。 如果我在 Python 3 中使用 from io import open 会发生什么?我目前不关心性能。 @matth 在 python3 中 open from io 是内置 open 的别名。见docs.python.org/3/library/io.html?highlight=io#io.open

以上是关于将 Python 3 open(encoding="utf-8") 向后移植到 Python 2的主要内容,如果未能解决你的问题,请参考以下文章

python成长之路9——文件操作open

python 文件操作1

关于python内open函数encoding编码问题

5 python--文件处理

Python学习笔记——文件操作

python 读不同编码的文本,传递一个可选的encoding 参数给open() 函数