Python:数据与文本?
Guido van Rossum在关于Python 3000的演讲中提到了一些内容,目的是为了让大家从Python 2过渡到Python 3时更顺利。他特别提到了文本处理,因为在Python 3中,字符串的唯一表示方式变成了Unicode,这是一个很大的变化。
关于文本处理,有一张幻灯片(第14张)提到:
- 在2.6版本中:
- 使用字节(bytes)和b'…'来表示所有数据(其实这些只是str和'…'的别名)
- 使用unicode和u'...'来表示所有文本
- 在2.5版本中:
- '...'表示数据,u'...'表示文本
我现在使用的是Python 2.6.4。这对我来说到底意味着什么呢?
在Python的世界里,数据和文本有什么区别呢?
2 个回答
你第一个问题的答案很简单:在Python 2.6中,你可以像以前一样使用。但是,如果你愿意,可以通过输入以下内容切换到Py3k标准:
from __future__ import unicode_literals
你第二个问题需要更详细的解释:
字符串是以人类可读的字符形式显示的数据。不仅在Python中,其他编程语言(我知道的)在处理字符串时也有各自的方法。
不过,大家都有一个共同点,就是编码。编码是将字节序列映射到符号(也就是大多数可打印的符号)的一种方式。
Python提供了一种简单的方法来处理编码的复杂性(当你在代码中放入字符串字面量时)。
让我们看一个非常简单的例子:
>>> len("Mañana")
7
我只看到6个符号。所以我期待len
会返回6。那这个额外的“符号”是从哪里来的呢?在UTF-8中,符号ñ
是用2个字节表示的。在Py3k之前,字符串字面量只是字节的序列。因此,Python把这个字符串看作字节,并且把它们都算上了:Ma\xc3\xb1ana
。
但是,如果我执行以下操作:
>>> len(u"Mañana")
6
所以Python“知道”这两个字节的序列“ñ”应该被视为一个字母。
这并不是Python独有的。下面的PHP脚本也表现出相同的行为:
manu@pavla:~$ php <<EOF
<?php
echo strlen("Mañana")."\n";
?>
EOF
7
PHP的解决方案相对复杂一些:
manu@pavla:~$ php <<EOF
<?php
echo mb_strlen("Mañana", "utf-8")."\n";
?>
EOF
6
注意我必须用mb_strlen
替代strlen
,并且我需要把utf-8
(编码)作为第二个参数传递。
提醒一下:用户提供的字符串通常是字节,而不是unicode字符串。所以你需要注意这一点。想了解更多,可以查看http://mail.python.org/pipermail/python-list/2008-July/139193.html
简单来说,Python 3(也叫Py3k)在处理文本和数据的方式上,可能是这个语言中最“破坏性”的变化。了解并尽量避免那些在Python 2.6中能正常工作的逻辑在3.x中表现不同的情况,可以帮助我们在迁移时减少麻烦。不过,我们也应该预期,2.6中的某些逻辑可能需要特别关注和修改,比如处理不同的编码等。
BDFL在第14张幻灯片上提出的建议,可能是希望大家开始“使用”Py3k支持的相同类型(仅限这些),也就是用unicode字符串表示文本(str
类型),用8位字节序列表示“数据”(bytes
类型)。
在上面那句话中,“使用”这个词用得比较宽泛,因为这两种类型在2.6和3.x版本中的语义和存储/编码方式是不同的。在Python 2.6中,字节类型和相关的字面量语法(b'xyz')实际上是映射到str类型的。因此
# in Py2.6
>>'mykey' == b'mykey'
True
b'mykey'.__class__
<class 'str'>
# in Py3k
>>>'mykey' == b'mykey'
False
b'mykey'.__class__
<class 'bytes'>
回答你下面评论中的问题,在2.6中,无论你使用b'xyz'还是'xyz',Python都把它理解为同一种东西:一个str。重要的是,你要理解这两者在未来可能是两种不同类型,且有不同的用途:
- str用于文本信息,
- bytes用于存储任意数据的字节序列。
举个例子,回到你的例子/问题,在Py3k中,你可以有一个字典,里面有两个相似的键,一个是b'mykey',另一个是'mykey',但在2.6中这是不可能的,因为这两个键实际上是一样的;关键是你要知道这些事情,并避免(或者在代码中明确标记)那些在2.6中能正常工作的代码在3.x中会出问题的情况。
在Py3k中,str是一个抽象的unicode字符串,是unicode字符的一个序列,Python会处理这些字符串与其编码形式之间的转换,无论编码是什么(作为程序员,你可以选择编码,但在处理字符串操作时不需要担心这些细节)。相对而言,bytes是一个8位“东西”的序列,其语义和编码完全由程序员决定。
所以,尽管Python 2.6看不出区别,通过明确使用bytes() / b'...'或str() / u'...',你...
- ...为自己和你的程序准备好即将到来的Py3k类型和语义
- ...让源代码的自动转换(比如2to3工具或其他工具)变得更简单,其中b在b'...'中会保留,而u在u'...'中会被去掉(因为唯一的字符串类型将是unicode)。
更多信息:
Python 2.6 新特性(查看PEP 3112字节字面量)
Python 3.0 新特性(查看顶部的文本与数据,而不是unicode与8位
)