将 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
而不是 open
。 io
是 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 的方式。
请注意,newline
、closefd
、opener
等某些 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的主要内容,如果未能解决你的问题,请参考以下文章