微观层面的变化和2to3无法充分解决的最大问题是默认字符串类型从字节流变成了Unicode。
如果您的代码需要处理编码和字节I/O,它将需要大量手动转换,以确保必须是字节的内容仍然是字节,并且在正确的阶段得到适当的解码。您会发现一些字符串方法(特别是format()
)和库调用需要Unicode字符串,因此即使它们实际上只是字节,您也需要额外的解码/编码循环来将其用作Unicode字符串。
这并不是因为一些Python标准库模块已经使用2to3进行了粗略的转换而没有正确关注字节/Unicode/编码问题所帮助的,因此它们本身关于哪种字符串类型是适用的也存在错误。其中一些正在处理中,但至少从Python 3.0到3.2,您将在像urllib、email和wsgiref这样需要了解字节编码的软件包中面临困惑和潜在的错误行为。
您可以通过小心地编写每个字符串文字来缓解问题。对于任何本质上基于字符的内容,请使用u''
字符串;对于任何真正的字节,请使用b''
字符串;对于“默认字符串”类型,在这种情况下并不重要或者您需要匹配库调用的字符串使用要求,使用''
。
不幸的是,b''
语法只在Python 2.6中引入,因此这样做会割裂早期版本的用户。
注:
它们之间有什么区别?
哦,天啊。嗯...
一个字节包含0-255范围内的值,并且可以表示大量二进制数据(例如图像内容)或一些文本,在这种情况下必须选择一种标准来将字符集映射到这些字节中。大多数这些“编码”标准都以相同的方式将正常的“ASCII”字符集映射到字节0-127中,因此在Python 2中仅处理ASCII文本时使用字节流通常是安全的。
如果您想在字节字符串中使用ASCII字符集之外的任何字符,则会遇到麻烦,因为每种编码都将不同的字符映射为剩余的128-255个字节值,并且大多数编码无法将每个可能的字符映射到字节。这就是为什么当您从一个语言环境加载文件到另一个语言环境的Windows应用程序中时,所有带重音符号或非拉丁字母的字母都会更改为错误的字母,从而产生一个难以阅读的混乱(也称为“乱码”)。
还有“多字节”编码,它们尝试通过使用多个字节来存储每个字符来适合更多的字符。这些编码是为东亚语言环境引入的,因为有非常多的汉字。但是还有UTF-8,这是一种设计更好的现代多字节编码,可以容纳每个字符。
如果您正在使用多字节编码的字节字符串(今天您可能会这样做,因为UTF-8被广泛使用;真正的现代应用程序不应使用其他编码),那么您会遇到更多问题,而不仅仅是跟踪您正在使用的编码。 len() 将告诉您以字节为单位的长度,而不是以字符为单位的长度,如果您开始索引和更改字节,则很可能将多字节序列分成两个部分,生成一个无效的序列并通常使一切变得混乱。
出于这个原因,Python 1.6及更高版本具有本机Unicode字符串(拼写为 u'something'),其中字符串中的每个单位都是一个字符,而不是一个字节。您可以对它们执行 len()、slice、replace、regex 等操作,并且它们总是表现得正确。对于文本处理任务,它们无疑更好,这就是为什么 Python 3 将它们作为默认字符串类型(无需在 '' 前加上 u)。问题在于许多现有的接口(如非Windows操作系统上的文件名、HTTP或SMTP)基本上是基于字节的,并且具有单独的指定编码方式。因此,当你处理需要字节的组件时,你必须注意正确地将 Unicode 字符串编码为字节,在 Python 3 中,你将不得不在一些之前不需要的地方明确地进行编码。
Unicode 字符串每个单位内部占用2个字节的存储空间是一种内部实现细节,你无法看到该存储空间;你不应以字节为单位来考虑它。你正在使用的单位是概念上的字符,无论 Python 如何选择在内存中表示它们。
...附言:
这并不完全正确。在 Windows 等“窄版本”的 Python 上,每个 Unicode 字符串单位不是技术上的字符,而是 UTF-16 的“代码单元”。对于 Basic Multilingual Plane 中的字符,从0x0000-0xFFFF,你不会注意到任何差异,但如果你使用位于这个 16 位范围之外的字符,即“星际平面”中的字符,则会发现它们需要两个单位而不是一个单位,同时,你会冒着在切片时分割字符的风险。
这相当糟糕,并且之所以会发生这种情况,是因为 Windows(和其他一些,例如 Java)在 Unicode 超过65,000个字符的限制之前,已经确定了使用 UTF-16 作为内存中的存储机制。然而,对于这些扩展字符的使用仍然相当罕见,任何在Windows上的人都会习惯于它们在许多应用程序中被破坏,因此对于你来说可能并不重要。
在“宽版本”中,Unicode 字符串由真正的字符“代码点”单位组成,因此甚至 BMP 之外的扩展字符也可以得到一致且易于处理的处理。为此需要付出的代价是效率:每个字符串单位在内存中占用4个字节的存储空间。
gb18030
:-) - John Machin