字符串和字节串有什么区别?
我正在使用一个库,它返回的是一种叫“字节串”的东西(bytes
),我需要把它转换成普通的字符串。
这两者之间真的有区别吗?它们有什么关系,我该怎么进行转换呢?
9 个回答
注意:我会详细说明我对Python 3的回答,因为Python 2的支持快要结束了。
在Python 3中
bytes
是由8位无符号值组成的序列,而str
是由表示人类语言文本字符的Unicode代码点组成的序列。
>>> # bytes
>>> b = b'h\x65llo'
>>> type(b)
<class 'bytes'>
>>> list(b)
[104, 101, 108, 108, 111]
>>> print(b)
b'hello'
>>>
>>> # str
>>> s = 'nai\u0308ve'
>>> type(s)
<class 'str'>
>>> list(s)
['n', 'a', 'i', '̈', 'v', 'e']
>>> print(s)
naïve
虽然bytes
和str
看起来可以一样使用,但它们之间并不兼容,也就是说,bytes
和str
不能一起用像>
和+
这样的运算符。此外,要记住,即使bytes
和str
的内容完全相同,使用==
比较它们是否相等时,结果总是False
。
>>> # concatenation
>>> b'hi' + b'bye' # this is possible
b'hibye'
>>> 'hi' + 'bye' # this is also possible
'hibye'
>>> b'hi' + 'bye' # this will fail
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't concat str to bytes
>>> 'hi' + b'bye' # this will also fail
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "bytes") to str
>>>
>>> # comparison
>>> b'red' > b'blue' # this is possible
True
>>> 'red'> 'blue' # this is also possible
True
>>> b'red' > 'blue' # you can't compare bytes with str
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '>' not supported between instances of 'bytes' and 'str'
>>> 'red' > b'blue' # you can't compare str with bytes
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '>' not supported between instances of 'str' and 'bytes'
>>> b'blue' == 'red' # equality between str and bytes always evaluates to False
False
>>> b'blue' == 'blue' # equality between str and bytes always evaluates to False
False
在处理bytes
和str
时,还有一个问题是与使用open
这个内置函数打开文件有关。一方面,如果你想从文件中读取或写入二进制数据,记得使用二进制模式打开文件,比如'rb'或'wb'。另一方面,如果你想从文件中读取或写入Unicode数据,要注意你电脑的默认编码,如果需要的话,可以传递encoding
参数,以避免出现意外情况。
在Python 2中
str
是由8位值组成的序列,而unicode
是由Unicode字符组成的序列。要记住的一点是,如果str
只包含7位ASCII字符,那么str
和unicode
可以一起使用运算符。
在Python 2中,使用辅助函数在str
和unicode
之间转换,以及在Python 3中在bytes
和str
之间转换,可能会很有用。
计算机能存储的唯一东西就是字节。
要在计算机中存储任何东西,首先必须进行编码,也就是把它转换成字节。例如:
MP3、WAV、PNG、JPEG、ASCII和UTF-8都是编码的例子。编码是一种将音频、图像、文本等表示为字节的格式。
在Python中,字节串就是一串字节。它对人来说是不可读的。在计算机内部,所有东西在存储之前都必须转换成字节串。
另一方面,字符串,通常简称为“字符串”,是一串字符。它是人类可读的。字符串不能直接存储在计算机中,必须先编码(转换成字节串)。有多种编码方式可以将字符串转换为字节串,比如ASCII和UTF-8。
'I am a string'.encode('ASCII')
上面的Python代码将使用ASCII编码对字符串'I am a string'进行编码。上述代码的结果将是一个字节串。如果你打印它,Python会将其表示为b'I am a string'
。不过要记住,字节串对人来说是不可读的,只是Python在你打印时会从ASCII解码它。在Python中,字节串用b
表示,后面跟着字节串的ASCII表示。
字节串可以被解码回字符串,只要你知道用于编码的格式。
b'I am a string'.decode('ASCII')
上述代码将返回原始字符串'I am a string'
。
编码和解码是相反的操作。所有东西在写入磁盘之前必须先编码,而在被人读取之前必须先解码。
假设你在使用Python 3(在Python 2中,这个区别稍微不那么明确)——字符串就是一串字符,也就是unicode编码点;这些是一个抽象的概念,不能直接存储在硬盘上。而字节串就是一串字节,顾名思义,这些东西是可以存储在硬盘上的。字符串和字节串之间的转换关系叫做编码——有很多种编码(实际上可能有无数种),你需要知道在特定情况下用哪种编码来进行转换,因为不同的编码可能会把相同的字节映射成不同的字符串:
>>> b'\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82'.decode('utf-16')
'蓏콯캁澽苏'
>>> b'\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82'.decode('utf-8')
'τoρνoς'
一旦你知道该用哪种编码,就可以使用字节串的.decode()
方法,从中得到正确的字符字符串。为了完整性,字符字符串的.encode()
方法则是反向操作:
>>> 'τoρνoς'.encode('utf-8')
b'\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82'