5

我正在尝试编写一个可以通过 python 2 和 3 运行的程序。它从网站读取字符并写入文件。我已经unicode_literals从 __future__ 导入了。

直接尝试编写如下所示的字符串:

txt = u'his$\u2026\n'

会导致 UnicodeEncodeError:

UnicodeEncodeError: 'ascii' codec can't encode character u'\u2026' in position 4: ordinal not in range(128)

在 python2 中将其写入文件的唯一方法是:

fp = open("/tmp/test", "w")
txt2 = txt.encode('utf-8')
fp.write(txt2) # It works
type(txt2) # str - that is why it works

但是,尝试在 python3 中重用相同的代码是行不通的,因为在 python 3 中,

type(txt2) # is byte type

例如

txt.encode('utf-8')
b'his$\xe2\x80\xa6\n'

强制 afp.write(txt2)会抛出 TypeError:

TypeError: write() argument must be str, not bytes

因此,可以txt = u'his$\u2026\n'在 python 2 和 3 中使用相同的代码块将其写入文件。(除了在 fp.write 上使用包装器)

4

2 回答 2

11

你说:

在 python2 中将其写入文件的唯一方法是:

fp = open("/tmp/test", "w")
txt2 = txt.encode('utf-8')
fp.write(txt2) # It works

但事实并非如此。有很多比这更好的方法。一个明显的方法是使用io.open. 在 3.x 中,这与内置函数相同open。在 2.6 和 2.7 中,它实际上是 3.x 内置的后向移植。这意味着您可以在两个版本中获得 3.x 样式的 Unicode 文本文件:

fp = io.open("/tmp/test", "w", encoding='utf-8')
fp.write(txt2) # It works

如果你需要兼容 2.5 或更早版本——或者可能是 2.6 和 3.0(它们支持io.open,但在某些情况下速度很慢),你可以使用旧的方式,codecs.open

fp = codecs.open("/tmp/test", "w", encoding='utf-8')
fp.write(txt2) # It works

两者之间存在差异,但是您编写的大多数代码不会对底层原始文件或编码器缓冲区或除基本的类文件对象 API 之外的任何其他内容感兴趣,因此您也可以使用try/except ImportError来回退到codecs如果io不可用。

于 2018-04-07T00:35:37.823 回答
1

使用该模式打开文件'b'将允许您在 Python2 和 Python3 中使用相同的代码:

txt = u'his$\u2026\n'

with open("/tmp/test", "wb") as fp:
    fp.write(txt.encode('utf-8'))

结果:

$ python2 x.py 
$ md5sum /tmp/test
f39cd7554a823b05658d776a27eb97d9  /tmp/test
$ python3 x.py 
$ md5sum /tmp/test
f39cd7554a823b05658d776a27eb97d9  /tmp/test
于 2018-04-07T00:41:21.810 回答