处理文本的最佳实践是 “Unicode三明治”

Unicode 三明治——目前处理文本的最佳实践

示意图:

要尽早把输入(例如读取文件时)的字节序列解码成字符串。这种三明治中的“肉片”是程序的业务逻辑,在这里只能处理字符串对象。在其他处理过程中,一定不能编码或解码。对输出来说,则要尽量晚地把字符串编码成字节序列。多数 Web 框架都是这样做的,使用框架时很少接触字节序列。例如,在 Django 中,视图应该输出 Unicode 字符串; Django 会负责把响应编码成字节序列,而且默认使用 UTF-8 编码。

Unicode三明治这种说法最早出现在 Ned Batchelder 在 US PyCon 2012 上所做的精彩演讲Pragmatic Unicode(很棒的演讲文稿)

在 Python 3 中能轻松地采纳 Unicode 三明治的建议,因为内置的 open 函数会在读取文件时做必要的解码,以文本模式写入文件时还会做必要的编码,所以调用 my_file.read() 方法得到的以及传给 my_file.write(text) 方法的都是字符串对象。

处理文本文件很简单。但是,如果依赖默认编码,你会遇到麻烦。不同平台、不同软件的默认编码不一定相同,文件的编码要相同才能顺利进行读写。

需要在多台设备中或多种场合下运行的代码,一定不能依赖默认编码。打开文件时始终应该明确传入 encoding= 参数,因为不同的设备使用的默认编码可能不同,有时隔一天也会发生变化。

在 GNU/Linux 和 OS X 中,编码的默认值都是 UTF-8,而且多年来都是如此,因此 I/O 能处理所有 Unicode 字符。在 Windows 中,不仅同一个系统中使用不同的编码,还有只支持 ASCII 和 127 个额外的字符的代码页(如 ‘cp850’ 或 ‘cp1252’),而且不同的代码页之间增加的字符也有所不同。因此,若不多加小心,Windows 用户更容易遇到编码问题。

因此,关于编码默认值的最佳建议是:别依赖默认值。 如果遵从 Unicode 三明治的建议,而且始终在程序中显式指定编码,那将避免很多问题。

整理自《流畅的Python》第4章关于文本文件的内容。