如何使用相同的代码将 unicode 文本写入 python 2 & 3 中的文件?

How to write unicode text to file in python 2 & 3 using same code?

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

导入了 unicode_literals

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

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 中重复使用相同的代码是行不通的,因为在 python3 中,

type(txt2) # is byte type

例如

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

强制 fp.write(txt2) 将抛出 TypeError:

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

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

你说:

The only way to write it to a file in python2 is:

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-style 两个版本的 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

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

使用 '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