2010-08-06 47 views
11

现在我们都知道了(我希望),Python 3正在慢慢开始取代Python 2.x.当然,在大多数现有代码被最终移植之前需要很多年的时间,但我们现在可以在2.x版本的代码中执行一些操作,以使开关更容易。准备从Python 2.x转换到3.x

很明显,在3.x中看看what's new会很有帮助,但是我们现在可以做些什么来使即将到来的转换更加轻松(并且如果需要,可以更容易地将更新输出到并发版本)?我特别想到可以开始使用脚本的行,这将使Python的早期版本更类似于3.x,但也欢迎其他习惯。

最明显的代码添加到,我能想到的脚本的顶部是:

from __future__ import division 
from __future__ import print_function 
try: 
    range = xrange 
except NameError: 
    pass 

最明显的习惯的东西我能想到的是字符串格式化 "{0} {1}!".format("Hello", "World")

任何其他线路和良好的习惯进入?

回答

12

微观层次变化和2to3无法充分解决的最大问题是从字节到Unicode的默认字符串类型。

如果你的代码需要对编码和字节I/O做任何事情,它需要大量的手工努力才能正确地进行转换,所以那些必须是字节的东西仍然是字节,并且在右边适当地解码阶段。您会发现某些字符串方法(特别是format())和库调用需要Unicode字符串,因此您可能需要额外的解码/编码循环才能将字符串用作Unicode,即使它们只是字节。

这并不是因为某些Python标准库模块被粗略地转换为2to3而没有适当关注字节/ unicode /编码问题,所以它们自己会犯错字符串类型是合适的。其中一些正在被淘汰,但至少从Python 3.0到3.2,您将面临来自像urllib,email和wsgiref等需要了解字节编码的软件包的混淆和潜在的错误行为。

您可以在每次编写字符串时小心谨慎地解决问题。将u''字符串用于固有字符的任何内容,b''字符串用于任何真正为字节的字符串,''用于“默认字符串”类型,其中无关紧要,或者您需要匹配库调用的字符串使用要求。

不幸的是,b''语法只在Python 2.6中引入,所以这样做会切断较早版本的用户。

ETA:

有什么区别?

哦,我的。好...

一个字节包含0-255范围内的一个值,可能表示二进制数据(例如图像内容)或某些文本的负载,在这种情况下必须选择标准将一组字符映射到这些字节中。这些“编码”标准中的大多数以相同的方式将正常的'ASCII'字符集映射到字节0-127,因此在Python 2中使用字节字符串仅用于ASCII纯文本处理通常是安全的。

如果你想要使用ASCII字符串之外的字符串中的任何字符,您遇到了麻烦,因为每种编码都将不同的字符集映射到其余字节值128-255,并且大多数编码无法映射每个可能的字符到字节。这是所有这些问题的根源,您将一个文件从一个语言环境加载到另一个语言环境的Windows应用程序中,并且所有重音或非拉丁字母都会更改为错误的文件,从而导致无法读取的混乱。 (又名'mojibake')。

还有'多字节'编码,它试图通过使用多个字节来存储每个字符来将更多字符装入可用空间。这些东西是为东亚语言环境引入的,因为有很多中文字符。但也有UTF-8,一个更好设计的现代多字节编码,可以容纳字符。

如果您正在处理多字节编码中的字节字符串 - 今天您可能会这样做,因为UTF-8使用非常广泛;实际上,在现代应用中不应该使用其他编码 - 那么你就会遇到更多的问题,而不是跟踪你正在使用的编码。 len()将以字节为单位告诉你长度,而不是以字符为单位的长度,如果你开始建立索引和改变字节,你很可能会将多字节序列分成两部分,产生一个无效序列,并且一般都会混淆所有内容。

因此,Python 1.6及更高版本具有原生Unicode字符串(拼写为u'something'),其中字符串中的每个单元都是字符而不是字节。你可以len()他们,切片他们,取代他们,正则表达他们,他们将永远行事适当。对于文本处理任务来说,它们毫无疑问更好,这就是为什么Python 3使它们成为默认字符串类型的原因(不必在''之前放置u)。

问题在于很多现有的接口(如Windows以外的操作系统上的文件名或HTTP或SMTP)主要是基于字节的,并且具有指定编码的单独方式。所以当你处理需要字节的组件时,你必须小心地将你的unicode字符串正确地编码为字节,而在Python 3中,你必须在某些不需要的地方明确地执行它。

这是一个内部实现细节,Unicode字符串在内部为每个单元存储“两个字节”的存储空间。你永远不会看到存储;你不应该用字节来考虑它。无论Python选择如何在内存中表示它们,您正在使用的单位在概念上都是字符。

...撇开:

这并不完全正确。在Python的“狭义构建”中,像Windows构建一样,Unicode字符串的每个单元在技术上不是字符,而是UTF-16的“代码单元”。对于基本多语言平面中的字符,从0x0000到0xFFFF,您不会注意到任何区别,但如果您使用的是16位范围以外的字符,那么在'星体平面'中的字符,您会发现两个单位,而不是一个单位,而且,当你切片时,你又冒险分割一个角色。

这是非常糟糕的,并且发生的原因是Windows(以及其他人,如Java)在Unicode超过65,000个字符限制之前以UTF-16作为内存存储机制。但是,使用这些扩展字符仍然非常少见,任何Windows上的用户都会习惯于破解很多应用程序,因此这对您来说可能并不重要。

在'广泛构建'上,Unicode字符串由真正的字符'代码点'单元构成,所以即使是BMP之外的扩展字符也能够一致且轻松地处理。支付的代价是效率:每个字符串单位在内存中占用四个字节的存储空间。

+0

说到字节和Unicode字符串,有什么区别?只有字节字符串每个字符使用一个字节,而unicode使用两个字节? – 2010-08-06 18:02:49

+0

“”“UTF-8 ...在现代应用程序中不应该使用其他编码”“,除非你的政府要求其他的东西,例如, 'gb18030' :-) – 2010-08-07 01:20:31

+0

这是关于字节字符串和Unicode之间差异的很好的解释。我或多或少熟悉ASCII与Uni​​code,但是(显然)我并不熟悉Python(尤其是3.x)如何处理它们。我希望我可以多次投票;) – 2010-08-12 16:53:21

5

我试图去习惯使用像var1//var2这样的东西,只要我真的想要整数除法(而不是浮点数)。对Python 3来说不是一大步,但至少我不必回去查看我所有的分区:)