我正在使用一个返回“字节字符串”(字节)的库,我需要将其转换为字符串。
这两者之间真的有区别吗?它们是如何关联的,我该如何进行转换?
我正在使用一个返回“字节字符串”(字节)的库,我需要将其转换为字符串。
这两者之间真的有区别吗?它们是如何关联的,我该如何进行转换?
当前回答
计算机唯一能存储的东西就是字节。
要在计算机中存储任何东西,首先必须对其进行编码,即将其转换为字节。例如:
如果你想要存储音乐,你必须首先使用MP3、WAV等对其进行编码。 如果你想要存储一张图片,你必须先用PNG、JPEG等对它进行编码。 如果想要存储文本,首先必须使用ASCII、UTF-8等对其进行编码。
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的生命周期已经非常接近了。
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位ASCI字符组成,则可以将str和unicode与操作符一起使用。
在Python 2中使用helper函数在str和unicode之间进行转换,在Python 3中使用bytes和str之间进行转换,可能会很有用。
Python语言包括str和bytes作为标准的“内置类型”。换句话说,它们都是类。我认为没有必要去解释为什么Python以这种方式实现。
尽管如此,str和bytes彼此非常相似。两者都有大部分相同的方法。下面的方法对于str类是唯一的:
casefold
encode
format
format_map
isdecimal
isidentifier
isnumeric
isprintable
以下方法对于bytes类是唯一的:
decode
fromhex
hex
简单地说,想想我们的自然语言,如英语、孟加拉语、汉语等。在说话时,所有这些语言都发出声音。但即使我们听到了,我们能听懂所有的吗?-
答案通常是否定的。所以,如果我说我懂英语,这意味着我知道这些声音是如何被编码成一些有意义的英语单词的,我只是用同样的方式解码这些声音来理解它们。所以,其他语言也是如此。如果你知道它,你就有了那种语言的编码器-解码器包,如果你不知道它,你就没有这个。
数字系统也是如此。就像我们自己一样,我们只能用耳朵听声音,用嘴巴发声,计算机只能存储字节和读取字节。因此,某个应用程序知道如何读取字节并解释它们(比如要考虑多少字节才能理解任何信息),并且以相同的方式编写,以便其其他应用程序也能理解它。但是如果没有理解(编码器-解码器),所有写入磁盘的数据都只是字节串。
让我们有一个简单的单字符字符串'š',并将其编码成一个字节序列:
>>> 'š'.encode('utf-8')
b'\xc5\xa1'
为了本例的目的,让我们以二进制形式显示字节序列:
>>> bin(int(b'\xc5\xa1'.hex(), 16))
'0b1100010110100001'
现在,如果不知道信息是如何编码的,通常是不可能解码回信息的。只有当你知道使用了UTF-8文本编码时,你才能按照解码UTF-8的算法获得原始字符串:
11000101 10100001
^^^^^ ^^^^^^
00101 100001
您可以将二进制数字101100001显示为字符串:
>>> chr(int('101100001', 2))
'š'
Assuming Python 3 (in Python 2, this difference is a little less well-defined) - a string is a sequence of characters, ie unicode codepoints; these are an abstract concept, and can't be directly stored on disk. A byte string is a sequence of, unsurprisingly, bytes - things that can be stored on disk. The mapping between them is an encoding - there are quite a lot of these (and infinitely many are possible) - and you need to know which applies in the particular case in order to do the conversion, since a different encoding may map the same bytes to a different string:
>>> 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'